commit f321fe5e6571d70fc1f2a00bded9a84f9e50394c Author: David Korth Date: Mon Jan 15 06:58:54 2018 -0500 Initial import of RVT-H Tool. This program will allow for managing Nintendo RVT-H Reader devkits, including dumping existing images and installing new images. The current version doesn't actually do anything. It's mostly a copy of the infrastructure from rom-properties, with some changes. In particular, we're using CMake's TARGET_COMPILE_FEATURES() instead of manually detecting C99 support. diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1ecda26 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +# Filetypes. +*~ +*.o +*.a +*.so +.directory +*.kate-swp + +# Build directories. +/build* + +# KDevelop project files. +*.kdev4 + +# CMake temproary files. +CMakeCache.txt +CMakeFiles/ +cmake_install.cmake +git_version.h diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d59a9a2 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,172 @@ +PROJECT(rvthtool-base) +CMAKE_MINIMUM_REQUIRED(VERSION 3.1) + +LIST(APPEND CMAKE_MODULE_PATH + "${CMAKE_SOURCE_DIR}/cmake/macros" + ) + +# If no build type is set, default to "Debug". +# TODO: Default to "Release"? +STRING(TOLOWER "${CMAKE_BUILD_TYPE}" TMP_BUILD_TYPE) +IF(TMP_BUILD_TYPE STREQUAL "") + SET(CMAKE_BUILD_TYPE "Release") +ELSEIF(TMP_BUILD_TYPE MATCHES "none") + SET(CMAKE_BUILD_TYPE "Release") +ENDIF() +UNSET(TMP_BUILD_TYPE) + +# Put all the binaries and libraries into a single directory. +# NOTE: CACHE INTERNAL is required in order to get this to work +# for KDE5 for some reason. (and maybe that's why KDE4 did this +# layout by default?) +SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" CACHE INTERNAL "Put all binaries in a single directory.") +SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE INTERNAL "Put all libraries in a single directory.") +SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/lib" CACHE INTERNAL "Put all archives in a single directory.") + +# Check for platform-specific functionality. +INCLUDE(cmake/platform.cmake NO_POLICY_SCOPE) + +# Program information. +SET(DESCRIPTION "RVT-H Tool") +SET(PACKAGE_NAME "rvthtool") +SET(AUTHOR "David Korth") +SET(VERSION_MAJOR 0) +SET(VERSION_MINOR 0) +SET(VERSION_PATCH 0) +SET(VERSION_DEVEL 1) +IF(VERSION_PATCH) + SET(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}") +ELSE(VERSION_PATCH) + SET(VERSION_STRING "${VERSION_MAJOR}.${VERSION_MINOR}") +ENDIF(VERSION_PATCH) +IF(VERSION_DEVEL) + SET(VERSION_STRING "${VERSION_STRING}+") +ENDIF(VERSION_DEVEL) +SET(VERSION_STRING_WIN32 "${VERSION_MAJOR},${VERSION_MINOR},${VERSION_PATCH},${VERSION_DEVEL}") + +# Split Debug macro. +# Also sets the image version for Windows builds. +INCLUDE(Win32ImageVersionLinkerFlags) +MACRO(DO_SPLIT_DEBUG _target) + IF(TARGET ${_target}) + # Split debug information. + INCLUDE(SetMSVCDebugPath) + SET_MSVC_DEBUG_PATH(${_target}) + IF(SPLIT_DEBUG) + INCLUDE(SplitDebugInformation) + SPLIT_DEBUG_INFORMATION(${_target}) + ENDIF(SPLIT_DEBUG) + # Set image version. + # Subprojects can override ${VERSION_MAJOR} and ${VERSION_MINOR}. + # FIXME: If minor version is e.g. "3", Windows interprets it as "03", + # so "1.3" will actually be "1.03". + WIN32_IMAGE_VERSION_LINKER_FLAGS(${VERSION_MAJOR} ${VERSION_MINOR}) + ENDIF(TARGET ${_target}) +ENDMACRO(DO_SPLIT_DEBUG) + +# Git version information. +FIND_PROGRAM(POSIX_SH sh) +IF(POSIX_SH) + # sh is available. + # Run the git version script. + IF(WIN32) + SET(ENV{SHELLOPTS} igncr) + ENDIF(WIN32) + ADD_CUSTOM_TARGET(git_version ALL + ${POSIX_SH} "${CMAKE_SOURCE_DIR}/git_version.sh" + -s "${CMAKE_SOURCE_DIR}" + -o "${CMAKE_BINARY_DIR}/git_version.h" + VERBATIM + ) +ELSE(POSIX_SH) + # sh isn't available. + # Create a blank git_version.h. + FILE(WRITE "${CMAKE_BINARY_DIR}/git_version.h" + "/* dummy file; POSIX sh is not available */\n") +ENDIF(POSIX_SH) + +# Make sure the file is deleted on `make clean`. +SET_PROPERTY(DIRECTORY APPEND + PROPERTY ADDITIONAL_MAKE_CLEAN_FILES "${CMAKE_BINARY_DIR}/git_version.h") + +# Reference: https://cmake.org/Wiki/RecipeAddUninstallTarget +########### Add uninstall target ############### +CONFIGURE_FILE( + "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake" + IMMEDIATE @ONLY) +ADD_CUSTOM_TARGET(uninstall + "${CMAKE_COMMAND}" -P "${CMAKE_CURRENT_BINARY_DIR}/cmake/cmake_uninstall.cmake") + +### Subdirectories. ### + +# Project subdirectories. +ADD_SUBDIRECTORY(src) + +# TODO: Print build summary indicating what plugins will be built. +# (Some other project had something like this...) +# TODO: Fail if no plugins are being built. + +# CPack settings. +SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${DESCRIPTION}") +SET(CPACK_PACKAGE_NAME "${PACKAGE_NAME}") +SET(CPACK_PACKAGE_VENDOR "${AUTHOR}") +SET(CPACK_PACKAGE_CONTACT "David Korth ") +SET(CPACK_PACKAGE_VERSION_MAJOR ${VERSION_MAJOR}) +SET(CPACK_PACKAGE_VERSION_MINOR ${VERSION_MINOR}) +SET(CPACK_PACKAGE_VERSION_PATCH ${VERSION_PATCH}) +SET(CPACK_PACKAGE_VERSION ${VERSION_STRING}) + +# TODO: DESCRIPTION and WELCOME files. +#SET(CPACK_PACKAGE_DESCRIPTION_FILE "${CMAKE_SOURCE_DIR}/doc/DESCRIPTION.txt") +SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/LICENSE") +SET(CPACK_RESOURCE_FILE_README "${CMAKE_SOURCE_DIR}/README.md") +#SET(CPACK_RESOURCE_FILE_WELCOME "${CMAKE_SOURCE_DIR}/doc/WELCOME.txt") + +# CPack: Source package settings. +# NOTE: Double-escape is required because the unescaped +# string # is written to CPackSourceConfig.cmake, which +# is then unescaped. +SET(CPACK_SOURCE_GENERATOR "TGZ") +SET(CPACK_SOURCE_IGNORE_FILES + "build.*/" + "build.*\\\\.sh" + "\\\\.git/" + "\\\\.gitignore" + "*\\\\.kate-swp" + ) + +IF(CMAKE_SYSTEM_PROCESSOR MATCHES "^(i.|x)86\$") + SET(CPACK_PACKAGE_SYSTEM_PROCESSOR "i386") +ELSEIF(CMAKE_SYSTEM_PROCESSOR MATCHES "^x86_64\$") + SET(CPACK_PACKAGE_SYSTEM_PROCESSOR "amd64") +ELSE() + SET(CPACK_PACKAGE_SYSTEM_PROCESSOR ${CMAKE_SYSTEM_PROCESSOR}) +ENDIF() + +IF(APPLE) + # TODO: Support for Mac OS X. +ELSEIF(WIN32) + IF(MSVC AND CMAKE_CL_64) + SET(WIN32_PACKAGE_SUFFIX "win64") + ELSEIF(NOT MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8) + SET(WIN32_PACKAGE_SUFFIX "win64") + ELSE() + SET(WIN32_PACKAGE_SUFFIX "win32") + ENDIF() + + SET(CPACK_GENERATOR "ZIP") + SET(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}_${CPACK_PACKAGE_VERSION}-${WIN32_PACKAGE_SUFFIX}") + SET(CPACK_INCLUDE_TOPLEVEL_DIRECTORY 0) +ENDIF() + +# Components. +SET(CPACK_COMPONENTS_ALL dll program debug doc i18n) +SET(CPACK_COMPONENT_DLL_DISPLAY_NAME "DLLs") +SET(CPACK_COMPONENT_PROGRAM_DISPLAY_NAME "Programs") +SET(CPACK_COMPONENT_DEBUG_DISPLAY_NAME "Debugging Symbols") +SET(CPACK_COMPONENT_DOC_DISPLAY_NAME "Documents") +SET(CPACK_COMPONENT_I18N_DISPLAY_NAME "Internationalization") + +# Initialize CPack. +INCLUDE(CPack) diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..601b5f5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,2 @@ +GNU General Public License, version 2 or any later version. +See GPL-2 or GPL-3 for the full text of these licenses. diff --git a/README.md b/README.md new file mode 100644 index 0000000..f9dd53c --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# RVT-H Tool diff --git a/cmake/cmake_uninstall.cmake.in b/cmake/cmake_uninstall.cmake.in new file mode 100644 index 0000000..1593f81 --- /dev/null +++ b/cmake/cmake_uninstall.cmake.in @@ -0,0 +1,23 @@ +# Reference: https://cmake.org/Wiki/RecipeAddUninstallTarget +IF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + MESSAGE(FATAL_ERROR "Cannot find install manifest: @CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") +ENDIF(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt") + +FILE(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files) +STRING(REGEX REPLACE " " ";" files "${files}") +STRING(REGEX REPLACE "\n" ";" files "${files}") +FOREACH(file ${files}) + MESSAGE(STATUS "Uninstalling $ENV{DESTDIR}${file}") + IF(EXISTS "$ENV{DESTDIR}${file}") + EXEC_PROGRAM( + "@CMAKE_COMMAND@" ARGS "-E remove $ENV{DESTDIR}${file}" + OUTPUT_VARIABLE rm_out + RETURN_VALUE rm_retval + ) + IF(NOT "${rm_retval}" STREQUAL 0) + MESSAGE(FATAL_ERROR "Problem when removing $ENV{DESTDIR}${file}") + ENDIF(NOT "${rm_retval}" STREQUAL 0) + ELSE(EXISTS "$ENV{DESTDIR}${file}") + MESSAGE(STATUS "File $ENV{DESTDIR}${file} does not exist.") + ENDIF(EXISTS "$ENV{DESTDIR}${file}") +ENDFOREACH(file) diff --git a/cmake/macros/64BitTimeSupport.c b/cmake/macros/64BitTimeSupport.c new file mode 100644 index 0000000..c3ce51d --- /dev/null +++ b/cmake/macros/64BitTimeSupport.c @@ -0,0 +1,18 @@ +/** + * 64-bit time_t test code. + * Reference: https://github.com/Benjamin-Dobell/Heimdall/blob/master/cmake/LargeFiles.c + */ + +#include +#include + +/** static_assert() macro copied from c++11-compat.h **/ +#define static_assert(expr, msg) switch (0) { case 0: case (expr): ; } + +int main(int argc, char *argv[]) +{ + static_assert(sizeof(time_t) == sizeof(int64_t), "time_t is the wrong size"); + int64_t tm64; + time_t tm = time(&tm64); + return 0; +} \ No newline at end of file diff --git a/cmake/macros/Check64BitTimeSupport.cmake b/cmake/macros/Check64BitTimeSupport.cmake new file mode 100644 index 0000000..a45c92e --- /dev/null +++ b/cmake/macros/Check64BitTimeSupport.cmake @@ -0,0 +1,80 @@ +# Check for 64-bit time support. +# Known cases: +# - Windows, MSVC: Supported as of MSVC 2005. +# - Windows, MinGW: Supported if -D__MINGW_USE_VC2005_COMPAT is defined. +# - 32-bit Linux: Supported in an upcoming glibc release. +# - 64-bit Linux: No macros are required. +# - 32-bit Mac OS X: Not supported. +# - 64-bit Mac OS X: No macros are required. + +# Partially based on: +# https://github.com/Benjamin-Dobell/Heimdall/blob/master/cmake/LargeFiles.cmake + +# This sets the following variables: +# - TIME64_FOUND: Set to 1 if 64-bit time_t is supported. +# - TIME64_FOUND_MINGW: Set to 1 if MinGW-w64's -D__MINGW_USE_VC2005_COMPAT is in use. +# - TIME64_FOUND_TIME_BITS: Set to 1 if glibc's -D_TIME_BITS=64 is in use. +# - TIME64_DEFINITIONS: Preprocessor macros required for large file support, if any. + +FUNCTION(CHECK_64BIT_TIME_SUPPORT) + IF(NOT DEFINED TIME64_FOUND) + # NOTE: ${CMAKE_MODULE_PATH} has two directories, macros/ and libs/, + # so we have to configure this manually. + SET(TIME64_SOURCE_PATH "${CMAKE_SOURCE_DIR}/cmake/macros") + + # Check for 64-bit time_t. + MESSAGE(STATUS "Checking if time_t is 64-bit") + IF(MSVC) + IF(MSVC_VERSION LESS 1310) + MESSAGE(STATUS "Checking if time_t is 64-bit - no") + MESSAGE(WARNING "MSVC 2005 (8.0) or later is required for 64-bit time_t.") + ELSE() + MESSAGE(STATUS "Checking if time_t is 64-bit - yes") + SET(TMP_TIME64_FOUND 1) + ENDIF() + ELSEIF(MINGW) + # MinGW should support 64-bit time_t if -D__MINGW_USE_VC2005_COMPAT is specified. + SET(TMP_TIME64_DEFINITIONS -D__MINGW_USE_VC2005_COMPAT) + TRY_COMPILE(TMP_TIME64_FOUND "${CMAKE_BINARY_DIR}" + "${TIME64_SOURCE_PATH}/64BitTimeSupport.c" + COMPILE_DEFINITIONS ${TMP_TIME64_DEFINITIONS}) + IF(TMP_TIME64_FOUND) + MESSAGE(STATUS "Checking if time_t is 64-bit - yes, using -D__MINGW_USE_VC2005_COMPAT") + SET(TMP_TIME64_FOUND_MINGW 1) + ELSE(TMP_TIME64_FOUND) + MESSAGE(STATUS "Checking if time_t is 64-bit - no") + MESSAGE(WARNING "MinGW-w64 is required for 64-bit time_t.") + UNSET(TMP_TIME64_DEFINITIONS) + ENDIF(TMP_TIME64_FOUND) + ELSE() + # Check if the OS supports 64-bit time_t out of the box. + TRY_COMPILE(TMP_TIME64_FOUND "${CMAKE_BINARY_DIR}" + "${TIME64_SOURCE_PATH}/64BitTimeSupport.c") + IF(TMP_TIME64_FOUND) + # Supported out of the box. + MESSAGE(STATUS "Checking if time_t is 64-bit - yes") + ELSE() + # Try adding 64-bit time_t macros. + # Reference: https://sourceware.org/glibc/wiki/Y2038ProofnessDesign?rev=115 + SET(TMP_TIME64_DEFINITIONS -D_TIME_BITS=64) + TRY_COMPILE(TMP_TIME64_FOUND "${CMAKE_BINARY_DIR}" + "${TIME64_SOURCE_PATH}/64BitTimeSupport.c" + COMPILE_DEFINITIONS ${TMP_TIME64_DEFINITIONS}) + IF(TMP_TIME64_FOUND) + # TIME64 macros work. + MESSAGE(STATUS "Checking if time_t is 64-bit - yes, using -D_TIME_BITS=64") + SET(TMP_TIME64_FOUND_TIME_BITS 1) + ELSE() + # TIME64 macros failed. + MESSAGE(STATUS "Checking if time_t is 64-bit - no") + UNSET(TMP_TIME64_DEFINITIONS) + ENDIF() + ENDIF() + ENDIF() + + SET(TIME64_FOUND ${TMP_TIME64_FOUND} CACHE INTERNAL "Is Large File Support available?") + SET(TIME64_FOUND_MINGW ${TMP_TIME64_FOUND_TIME_BITS} CACHE INTERNAL "64-bit time_t is available using -D__MINGW_USE_VC2005_COMPAT") + SET(TIME64_FOUND_TIME_BITS ${TMP_TIME64_FOUND_TIME_BITS} CACHE INTERNAL "64-bit time_t is available using -D_TIME_BITS=64") + SET(TIME64_DEFINITIONS "${TMP_TIME64_DEFINITIONS}" CACHE INTERNAL "Definitions required for 64-bit time_t") + ENDIF() +ENDFUNCTION(CHECK_64BIT_TIME_SUPPORT) diff --git a/cmake/macros/CheckHiddenVisibility.cmake b/cmake/macros/CheckHiddenVisibility.cmake new file mode 100644 index 0000000..fe5932d --- /dev/null +++ b/cmake/macros/CheckHiddenVisibility.cmake @@ -0,0 +1,27 @@ +# Check what flags are needed for hidden visibility. +# Usage: CHECK_HIDDEN_VISIBILITY() +# +# NOTE: Do NOT use this for extlibs, since many extlibs, including +# zlib, don't work properly if symbols aren't visible by default. + +MACRO(CHECK_HIDDEN_VISIBILITY) + # Check for visibility symbols. + IF(NOT CMAKE_VERSION VERSION_LESS 3.3.0) + # CMake 3.3: Use CMake predefined variables. + # NOTE: CMake 3.0-3.2 do not apply these settings + # to static libraries, so we have to fall back to the + # "deprecated" ADD_COMPILER_EXPORT_FLAGS(). + CMAKE_POLICY(SET CMP0063 NEW) + SET(CMAKE_C_VISIBILITY_PRESET "hidden") + SET(CMAKE_CXX_VISIBILITY_PRESET "hidden") + SET(CMAKE_VISIBILITY_INLINES_HIDDEN ON) + ELSE() + # CMake 2.x, 3.0-3.2: Use ADD_COMPILER_EXPORT_FLAGS(). + # NOTE: 3.0+ will show a deprecation warning. + INCLUDE(GenerateExportHeader) + ADD_COMPILER_EXPORT_FLAGS(RP_COMPILER_EXPORT_FLAGS) + SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${RP_COMPILER_EXPORT_FLAGS}") + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RP_COMPILER_EXPORT_FLAGS}") + UNSET(RP_COMPILER_EXPORT_FLAGS) + ENDIF() +ENDMACRO() diff --git a/cmake/macros/CheckLargeFileSupport.cmake b/cmake/macros/CheckLargeFileSupport.cmake new file mode 100644 index 0000000..e475912 --- /dev/null +++ b/cmake/macros/CheckLargeFileSupport.cmake @@ -0,0 +1,78 @@ +# Check for Large File Support. +# Known cases: +# - Windows, MSVC: No macros are needed, but 64-bit functions must be +# used explicitly, e.g. _fseeki64() and _ftelli64(). libW32U +# provides macro redefinitions for this. +# - Windows, MinGW: LFS functions fseeko() and ftello() are present. +# LFS Macros are required for large files. +# - 32-bit Linux: LFS macros are required. +# - 64-bit Linux: No macros are required. +# - All Mac OS X: No macros are required. + +# Partially based on: +# https://github.com/Benjamin-Dobell/Heimdall/blob/master/cmake/LargeFiles.cmake + +# This sets the following variables: +# - LFS_FOUND: Set to 1 if LFS is supported. +# - LFS_FOUND_FSEEKO: Set to 1 if LFS is supported using fseeko(). +# - LFS_FOUND_FSEEKI64: Set to 1 if LFS is supported using _fseeki64(). +# - LFS_DEFINITIONS: Preprocessor macros required for large file support, if any. + +# TODO: Use _fseeki64() and _ftelli64() on MinGW to avoid +# the use of wrapper functions? + +FUNCTION(CHECK_LARGE_FILE_SUPPORT) + IF(NOT DEFINED LFS_FOUND) + # NOTE: ${CMAKE_MODULE_PATH} has two directories, macros/ and libs/, + # so we have to configure this manually. + SET(LFS_SOURCE_PATH "${CMAKE_SOURCE_DIR}/cmake/macros") + + # Check for LFS. + MESSAGE(STATUS "Checking if Large File Support is available") + IF(MSVC) + # Check if _fseeki64() and _ftelli64() are available. + TRY_COMPILE(TMP_LFS_FOUND "${CMAKE_BINARY_DIR}" + "${LFS_SOURCE_PATH}/LargeFileSupport_fseeki64.c") + IF(TMP_LFS_FOUND) + # _fseeki64() and _ftelli64() are available. + MESSAGE(STATUS "Checking if Large File Support is available - yes, using MSVC non-standard functions") + SET(TMP_LFS_FOUND_FSEEKI64 1) + ELSE() + # Not available... + MESSAGE(STATUS "Checking if Large File Support is available - no") + MESSAGE(WARNING "MSVC 2005 (8.0) or later is required for Large File Support.") + ENDIF() + ELSE() + # Check if the OS supports Large Files out of the box. + TRY_COMPILE(TMP_LFS_FOUND "${CMAKE_BINARY_DIR}" + "${LFS_SOURCE_PATH}/LargeFileSupport_fseeko.c") + IF(TMP_LFS_FOUND) + # Supported out of the box. + MESSAGE(STATUS "Checking if Large File Support is available - yes") + ELSE() + # Try adding LFS macros. + SET(TMP_LFS_DEFINITIONS -D_LARGEFILE_SOURCE=1 -D_LARGEFILE64_SOURCE=1 -D_FILE_OFFSET_BITS=64) + TRY_COMPILE(TMP_LFS_FOUND "${CMAKE_BINARY_DIR}" + "${LFS_SOURCE_PATH}/LargeFileSupport_fseeko.c" + COMPILE_DEFINITIONS ${TMP_LFS_DEFINITIONS}) + IF(TMP_LFS_FOUND) + # LFS macros work. + MESSAGE(STATUS "Checking if Large File Support is available - yes, using LFS macros") + SET(TMP_LFS_FOUND_FSEEKO 1) + # NOTE: COMPILE_DEFINITIONS requires a semicolon-separated list; + # CFLAGS reqiures space-separated. + STRING(REPLACE ";" " " TMP_LFS_DEFINITIONS "${TMP_LFS_DEFINITIONS}") + ELSE() + # LFS macros failed. + MESSAGE(STATUS "Checking if Large File Support is available - no") + UNSET(TMP_LFS_DEFINITIONS) + ENDIF() + ENDIF() + ENDIF() + + SET(LFS_FOUND ${TMP_LFS_FOUND} CACHE INTERNAL "Is Large File Support available?") + SET(LFS_FOUND_FSEEKO ${TMP_LFS_FOUND_FSEEKO} CACHE INTERNAL "Large File Support is available using LFS macros") + SET(LFS_FOUND_FSEEKI64 ${TMP_LFS_FOUND_FSEEKI64} CACHE INTERNAL "Large File Support is available using MSVC non-standard functions") + SET(LFS_DEFINITIONS "${TMP_LFS_DEFINITIONS}" CACHE INTERNAL "Definitions required for Large File Support") + ENDIF() +ENDFUNCTION(CHECK_LARGE_FILE_SUPPORT) diff --git a/cmake/macros/CheckStackProtectorCompilerFlag.cmake b/cmake/macros/CheckStackProtectorCompilerFlag.cmake new file mode 100644 index 0000000..f08db85 --- /dev/null +++ b/cmake/macros/CheckStackProtectorCompilerFlag.cmake @@ -0,0 +1,116 @@ +# - Check what flag is needed to enable stack smashing protection +# CHECK_STACK_PROTECTOR_COMPILER_FLAG(VARIABLE) +# +# VARIABLE - variable to store the result +# +# This actually calls the check_c_source_compiles macro. +# See help for CheckCSourceCompiles for a listing of variables +# that can modify the build. + +# Copyright (c) 2006, Alexander Neundorf, +# C++ 2011 version Copyright (c) 2011 by David Korth. +# +# Redistribution and use is allowed according to the terms of the BSD license. +# For details see the accompanying COPYING-CMAKE-SCRIPTS file. + +# Based on CHECK_C99_COMPILER_FLAG(). (CheckC99CompilerFlag.cmake) + +INCLUDE(CheckCSourceCompiles) + +MACRO(CHECK_STACK_PROTECTOR_COMPILER_FLAG _RESULT) + UNSET(${_RESULT}) + + IF(MSVC) + # MSVC 2002 introduced the /GS option. + # MSVC 2005+ enables it by default. + IF(MSVC_VERSION GREATER 1399) + # MSVC 2005+. + MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: none") + ELSEIF(MSVC_VERSION GREATER 1299) + # MSVC 2002 or 2003. + SET(${_RESULT} "/GS") + MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: ${${_RESULT}}") + ELSE() + # MSVC 2002 or earlier. + MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: not available") + ENDIF() + ELSE(MSVC) + # gcc-4.1: -fstack-protector, -fstack-protector-all + # gcc-4.9: -fstack-protector-strong + MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection:") + FOREACH(CHECK_STACK_CFLAG "-fstack-protector-strong" "-fstack-protector-all" "-fstack-protector") + # CMake doesn't like "+" characters in variable names. + STRING(REPLACE "+" "_" CHECK_STACK_CFLAG_VARNAME "CHECK_CFLAG_${CHECK_STACK_CFLAG}") + + SET(SAFE_CMAKE_REQUIRED_DEFINITIONS "${CMAKE_REQUIRED_DEFINITIONS}") + SET(SAFE_CMAKE_REQUIRED_LIBRARIES "${CMAKE_REQUIRED_LIBRARIES}") + SET(CMAKE_REQUIRED_DEFINITIONS "${CHECK_STACK_CFLAG}") + IF(WIN32) + SET(CMAKE_REQUIRED_LIBRARIES "-lkernel32") + ELSE(WIN32) + SET(CMAKE_REQUIRED_LIBRARIES "-lc") + ENDIF(WIN32) + # NOTE: We need a function that triggers stack smashing protection + # in order to determine if libssp is needed on MinGW-w64. + # Based on wrapper functions in c99-compat.msvcrt.h. + CHECK_C_SOURCE_COMPILES(" +#include +#include + +#ifndef _MSC_VER +#define _vsnprintf vsnprintf +#endif + +int C99_vsnprintf(char *str, size_t size, const char *format, va_list ap) +{ + int ret = _vsnprintf(str, size, format, ap); + if (ret >= (int)size) { + // Make sure the buffer is NULL-terminated. + str[size-1] = 0; + } else if (ret < 0) { + // Make sure the buffer is empty. + // MSVCRT *should* do this, but just in case... + str[0] = 0; + } + return ret; +} + +int C99_snprintf(char *str, size_t size, const char *format, ...) +{ + int ret; + va_list ap; + va_start(ap, format); + ret = C99_vsnprintf(str, size, format, ap); + va_end(ap); + return ret; +} + +int main(int argc, char *argv[]) +{ + char buf[128]; + snprintf(buf, sizeof(buf), \"test: %s\", argv[0]); + puts(buf); + return 0; +}" ${CHECK_STACK_CFLAG_VARNAME}) + SET(CMAKE_REQUIRED_DEFINITIONS "${SAFE_CMAKE_REQUIRED_DEFINITIONS}") + SET(CMAKE_REQUIRED_LIBRARIES "${SAFE_CMAKE_REQUIRED_LIBRARIES}") + + IF(${${CHECK_STACK_CFLAG_VARNAME}}) + SET(${_RESULT} ${CHECK_STACK_CFLAG}) + UNSET(${CHECK_STACK_CFLAG_VARNAME}) + UNSET(CHECK_STACK_CFLAG_VARNAME) + BREAK() + ENDIF(${${CHECK_STACK_CFLAG_VARNAME}}) + UNSET(${CHECK_STACK_CFLAG_VARNAME}) + UNSET(CHECK_STACK_CFLAG_VARNAME) + UNSET(SAFE_CMAKE_REQUIRED_DEFINITIONS) + UNSET(SAFE_CMAKE_REQUIRED_LIBRARIES) + ENDFOREACH() + IF(${_RESULT}) + MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: ${${_RESULT}}") + ELSE(${_RESULT}) + MESSAGE(STATUS "Checking what CFLAG is required for stack smashing protection: not available") + MESSAGE(WARNING "Stack smashing protection is not available.\nPlease check your toolchain installation.") + ENDIF(${_RESULT}) + ENDIF(MSVC) +ENDMACRO(CHECK_STACK_PROTECTOR_COMPILER_FLAG) diff --git a/cmake/macros/DirInstallPaths.cmake b/cmake/macros/DirInstallPaths.cmake new file mode 100644 index 0000000..f21c8cd --- /dev/null +++ b/cmake/macros/DirInstallPaths.cmake @@ -0,0 +1,77 @@ +# Directory install paths. +# Files are installed in different directories depending +# on platform, e.g. Unix-style for Linux and most other +# Unix systems. + +# NOTE: DIR_INSTALL_DOC_ROOT is for documents that should +# be in the root of the Windows ZIP file. On other platforms, +# it's the same as DIR_INSTALL_DOC. + +IF(NOT PACKAGE_NAME) + MESSAGE(FATAL_ERROR "PACKAGE_NAME is not set.") +ENDIF(NOT PACKAGE_NAME) + +# Architecture name for arch-specific paths. +STRING(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" arch) +IF(arch MATCHES "^(i.|x)86$|^x86_64$|^amd64$") + # i386/amd64. Check sizeof(void*) for the actual architecture, + # since building 32-bit on 64-bit isn't considered "cross-compiling", + # so CMAKE_SYSTEM_PROCESSOR might not be accurate. + # NOTE: Checking CMAKE_CL_64 instead of sizeof(void*) for MSVC builds. + IF(MSVC AND CMAKE_CL_64) + SET(arch "amd64") + ELSEIF(NOT MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8) + SET(arch "amd64") + ELSE() + SET(arch "i386") + ENDIF() +ENDIF(arch MATCHES "^(i.|x)86$|^x86_64$|^amd64$") + +INCLUDE(GNUInstallDirs) +IF(UNIX AND NOT APPLE) + # Unix-style install paths. + # NOTE: CMake doesn't use Debian-style multiarch for libexec, + # so we have to check for that. + IF(CMAKE_INSTALL_LIBDIR MATCHES .*gnu.*) + SET(CMAKE_INSTALL_LIBEXECDIR "${CMAKE_INSTALL_LIBDIR}/libexec" CACHE "libexec override for Debian multi-arch" INTERNAL FORCE) + SET(CMAKE_INSTALL_FULL_LIBEXECDIR "${CMAKE_INSTALL_FULL_LIBDIR}/libexec" CACHE "libexec override for Debian multi-arch" INTERNAL FORCE) + ENDIF() + SET(DIR_INSTALL_EXE "${CMAKE_INSTALL_BINDIR}") + SET(DIR_INSTALL_DLL "${CMAKE_INSTALL_LIBDIR}") + SET(DIR_INSTALL_LIB "${CMAKE_INSTALL_LIBDIR}") + SET(DIR_INSTALL_LIBEXEC "${CMAKE_INSTALL_LIBEXECDIR}") + SET(DIR_INSTALL_LOCALE "share/locale") + SET(DIR_INSTALL_DOC "share/doc/${PACKAGE_NAME}") + SET(DIR_INSTALL_DOC_ROOT "${DIR_INSTALL_DOC}") + SET(DIR_INSTALL_EXE_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_EXE}") + SET(DIR_INSTALL_DLL_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_DLL}") + SET(DIR_INSTALL_LIB_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_LIB}") + SET(DIR_INSTALL_LIBEXEC_DEBUG "lib/debug/${CMAKE_INSTALL_PREFIX}/${DIR_INSTALL_LIBEXEC}") +ELSEIF(APPLE) + # Mac OS X-style install paths. + # Install should be relative to the application bundle. + # TODO: Not supported... + MESSAGE(STATUS "WARNING: Mac OS X is not officially supported yet.") +ELSEIF(WIN32) + # Win32-style install paths. + # Files are installed relative to root, since the + # program is run out of its own directory. + SET(DIR_INSTALL_EXE "${arch}") + SET(DIR_INSTALL_DLL "${arch}") + SET(DIR_INSTALL_LIB "${arch}") + SET(DIR_INSTALL_LIBEXEC "${arch}") + SET(DIR_INSTALL_LOCALE "locale") + SET(DIR_INSTALL_DOC "doc") + SET(DIR_INSTALL_DOC_ROOT ".") + SET(DIR_INSTALL_EXE_DEBUG "debug") + # Installing debug symbols for DLLs in the + # same directory as the DLL. + SET(DIR_INSTALL_EXE_DEBUG "${DIR_INSTALL_EXE}") + SET(DIR_INSTALL_DLL_DEBUG "${DIR_INSTALL_DLL}") + SET(DIR_INSTALL_LIB_DEBUG "${DIR_INSTALL_LIB}") + SET(DIR_INSTALL_LIBEXEC_DEBUG "${DIR_INSTALL_LIBEXEC}") +ELSE() + MESSAGE(WARNING "Installation paths have not been set up for this system.") +ENDIF() + +UNSET(arch) diff --git a/cmake/macros/LargeFileSupport_fseeki64.c b/cmake/macros/LargeFileSupport_fseeki64.c new file mode 100644 index 0000000..47b503b --- /dev/null +++ b/cmake/macros/LargeFileSupport_fseeki64.c @@ -0,0 +1,15 @@ +/** + * Large File Support test code: _fseeki64(), _ftelli64() [MSVC] + * Reference: https://github.com/Benjamin-Dobell/Heimdall/blob/master/cmake/LargeFilesWindows.c + */ + +#include + +int main(int argc, const char **argv) +{ + // _fseeki64() and _ftelli64() use __int64. + // NOTE: __int64 is an MSVC-proprietary type. + __int64 offset = _ftelli64(NULL); + _fseeki64(NULL, offset, SEEK_SET); + return 0; +} diff --git a/cmake/macros/LargeFileSupport_fseeko.c b/cmake/macros/LargeFileSupport_fseeko.c new file mode 100644 index 0000000..609bdf1 --- /dev/null +++ b/cmake/macros/LargeFileSupport_fseeko.c @@ -0,0 +1,20 @@ +/** + * Large File Support test code: fseeko(), ftello() [LFS] + * Reference: https://github.com/Benjamin-Dobell/Heimdall/blob/master/cmake/LargeFiles.c + */ + +#include +#include +#include +#include + +/** static_assert() macro copied from c++11-compat.h **/ +#define static_assert(expr, msg) switch (0) { case 0: case (expr): ; } + +int main(int argc, const char **argv) +{ + static_assert(sizeof(off_t) == sizeof(int64_t), "off_t is the wrong size"); + off_t offset = ftello(NULL); + fseeko(NULL, offset, SEEK_SET); + return 0; +} \ No newline at end of file diff --git a/cmake/macros/SetMSVCDebugPath.cmake b/cmake/macros/SetMSVCDebugPath.cmake new file mode 100644 index 0000000..7a9bf5a --- /dev/null +++ b/cmake/macros/SetMSVCDebugPath.cmake @@ -0,0 +1,54 @@ +# Split debug information from an executable into a separate file. +# SPLIT_DEBUG_INFORMATION(EXE_TARGET) +# +# References: +# - http://cmake.3232098.n2.nabble.com/Save-stripped-debugging-information-td6819195.html +# - http://sourceware.org/bugzilla/show_bug.cgi?id=14527 +# - If debug symbols are stripped before .gnu_debuglink is added, +# the section will be truncated to .gnu_deb, and hence won't +# be recognized by gdb. +# - FIXME: If the above .gnu_debuglink workaround is used, Windows XP +# and Windows 7 will claim that the executable isn't a valid Win32 +# executable. (Wine ignores it and works fine!) +# +MACRO(SET_MSVC_DEBUG_PATH _target) +IF(MSVC) + # CMake seems to use weird settings for the PDB file. + # (at least version 2.8.12.2; 3.0.0 might be different) + STRING(REGEX REPLACE + "/Fd/" + "/Fd" + CMAKE_C_COMPILE_OBJECT "${CMAKE_C_COMPILE_OBJECT}") + STRING(REGEX REPLACE + "/Fd/" + "/Fd" + CMAKE_CXX_COMPILE_OBJECT "${CMAKE_CXX_COMPILE_OBJECT}") + + # Handle target prefixes if not overridden. + # NOTE: Cannot easily use the TYPE property in a generator expression... + GET_PROPERTY(TARGET_TYPE TARGET ${_target} PROPERTY TYPE) + SET(PREFIX_EXPR_1 "$<$,>:${CMAKE_${TARGET_TYPE}_PREFIX}>") + SET(PREFIX_EXPR_2 "$<$,>>:$>") + SET(PREFIX_EXPR_FULL "${PREFIX_EXPR_1}${PREFIX_EXPR_2}") + + # If a custom OUTPUT_NAME was specified, use it. + SET(OUTPUT_NAME_EXPR_1 "$<$,>:${_target}>") + SET(OUTPUT_NAME_EXPR_2 "$<$,>>:$>") + SET(OUTPUT_NAME_EXPR "${OUTPUT_NAME_EXPR_1}${OUTPUT_NAME_EXPR_2}") + SET(OUTPUT_NAME_FULL "${PREFIX_EXPR_FULL}${OUTPUT_NAME_EXPR}$") + + SET(SPLITDEBUG_SOURCE "$") + SET(SPLITDEBUG_TARGET "$/${OUTPUT_NAME_FULL}.debug") + + SET(OUTPUT_NAME_EXPR_1 "$$$") + SET(OUTPUT_NAME_EXPR_2 "$<$,>:$${_target}$>") + + # Set the target PDB filename. + SET_TARGET_PROPERTIES(${_target} + PROPERTIES PDB "$/${OUTPUT_NAME_EXPR_1}${OUTPUT_NAME_EXPR_2}.pdb" + ) + + UNSET(OUTPUT_NAME_EXPR_1) + UNSET(OUTPUT_NAME_EXPR_2) +ENDIF(MSVC) +ENDMACRO(SET_MSVC_DEBUG_PATH) diff --git a/cmake/macros/SplitDebugInformation.cmake b/cmake/macros/SplitDebugInformation.cmake new file mode 100644 index 0000000..36b0caf --- /dev/null +++ b/cmake/macros/SplitDebugInformation.cmake @@ -0,0 +1,78 @@ +# Split debug information from an executable into a separate file. +# SPLIT_DEBUG_INFORMATION(EXE_TARGET) +# +# References: +# - http://cmake.3232098.n2.nabble.com/Save-stripped-debugging-information-td6819195.html +# - http://sourceware.org/bugzilla/show_bug.cgi?id=14527 +# - If debug symbols are stripped before .gnu_debuglink is added, +# the section will be truncated to .gnu_deb, and hence won't +# be recognized by gdb. +# - FIXME: If the above .gnu_debuglink workaround is used, Windows XP +# and Windows 7 will claim that the executable isn't a valid Win32 +# executable. (Wine ignores it and works fine!) +# +IF(NOT MSVC) + INCLUDE(CMakeFindBinUtils) + IF(NOT CMAKE_OBJCOPY) + MESSAGE(WARNING "'objcopy' was not found; debug information will not be split.") + SET(INSTALL_DEBUG OFF CACHE "" INTERNAL FORCE) + ELSEIF(NOT CMAKE_STRIP) + MESSAGE(WARNING "'strip' was not found; debug information will not be split.") + SET(INSTALL_DEBUG OFF CACHE "" INTERNAL FORCE) + ENDIF() +ENDIF(NOT MSVC) + +FUNCTION(SPLIT_DEBUG_INFORMATION _target) +SET(SPLIT_OK 1) +IF(MSVC) + # MSVC splits debug information by itself. + SET(SPLIT_OK 0) +ELSEIF(NOT CMAKE_OBJCOPY) + # 'objcopy' is missing. + SET(SPLIT_OK 0) +ELSEIF(NOT CMAKE_STRIP) + # 'strip' is missing. + SET(SPLIT_OK 0) +ENDIF() + +IF(SPLIT_OK) + # Handle target prefixes if not overridden. + # NOTE: Cannot easily use the TYPE property in a generator expression... + GET_PROPERTY(TARGET_TYPE TARGET ${_target} PROPERTY TYPE) + SET(PREFIX_EXPR_1 "$<$,>:${CMAKE_${TARGET_TYPE}_PREFIX}>") + SET(PREFIX_EXPR_2 "$<$,>>:$>") + SET(PREFIX_EXPR_FULL "${PREFIX_EXPR_1}${PREFIX_EXPR_2}") + + # If a custom OUTPUT_NAME was specified, use it. + SET(OUTPUT_NAME_EXPR_1 "$<$,>:${_target}>") + SET(OUTPUT_NAME_EXPR_2 "$<$,>>:$>") + SET(OUTPUT_NAME_EXPR "${OUTPUT_NAME_EXPR_1}${OUTPUT_NAME_EXPR_2}") + + SET(OUTPUT_NAME_FULL "${PREFIX_EXPR_FULL}${OUTPUT_NAME_EXPR}$") + + SET(SPLITDEBUG_SOURCE "$") + SET(SPLITDEBUG_TARGET "$/${OUTPUT_NAME_FULL}.debug") + + # NOTE: objcopy --strip-debug does NOT fully + # strip the binary; two sections are left: + # - .symtab: Symbol table. + # - .strtab: String table. + # These sections are split into the .debug file, so there's + # no reason to keep them in the executable. + ADD_CUSTOM_COMMAND(TARGET ${_target} POST_BUILD + COMMAND ${CMAKE_OBJCOPY} --only-keep-debug + ${SPLITDEBUG_SOURCE} ${SPLITDEBUG_TARGET} + COMMAND ${CMAKE_STRIP} + ${SPLITDEBUG_SOURCE} + COMMAND ${CMAKE_OBJCOPY} --add-gnu-debuglink="${SPLITDEBUG_TARGET}" + ${SPLITDEBUG_SOURCE} + ) + + # Set the target property to allow installation. + SET_TARGET_PROPERTIES(${_target} PROPERTIES PDB ${SPLITDEBUG_TARGET}) + + # Make sure the file is deleted on `make clean`. + SET_PROPERTY(DIRECTORY APPEND + PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${SPLITDEBUG_TARGET}) +ENDIF(SPLIT_OK) +ENDFUNCTION(SPLIT_DEBUG_INFORMATION) diff --git a/cmake/macros/Win32ImageVersionLinkerFlags.cmake b/cmake/macros/Win32ImageVersionLinkerFlags.cmake new file mode 100644 index 0000000..2ec4892 --- /dev/null +++ b/cmake/macros/Win32ImageVersionLinkerFlags.cmake @@ -0,0 +1,35 @@ +# Win32 image version linker flags. +# Determines the appropriate flags to use with MinGW and MSVC. +# The TARGET_VERSION field causes executables to be named +# program.exe-1.0 when built with MinGW, so we can't use it. +# +# The appropriate flags are automatically appended to +# CMAKE_EXE_LINKER_FLAGS_(DEBUG|RELEASE) and +# CMAKE_SHARED_LINKER_FLAGS_(DEBUG|RELEASE). + +MACRO(WIN32_IMAGE_VERSION_LINKER_FLAGS _major_version _minor_version) +IF(WIN32) + IF(MSVC) + SET(_remove_flags "/version:.") + SET(_linker_flags "-version:${_major_version}.${_minor_version}") + ELSEIF(MINGW) + # NOTE: Also ${CMAKE_GNULD_IMAGE_VERSION}. + SET(_remove_flags "-Wl,--major-image-version,,--minor-image-version,") + SET(_linker_flags "-Wl,--major-image-version,${_major_version},--minor-image-version,${_minor_version}") + ELSE() + MESSAGE(FATAL_ERROR "Unknown Windows compiler, please fix WIN32_IMAGE_VERSION_LINKER_FLAGS.") + ENDIF() + + # Replace the version flags. + STRING(REPLACE "${_remove_flags}" "${_linker_flags}" CMAKE_C_CREATE_SHARED_MODULE "${CMAKE_C_CREATE_SHARED_MODULE}") + STRING(REPLACE "${_remove_flags}" "${_linker_flags}" CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY}") + STRING(REPLACE "${_remove_flags}" "${_linker_flags}" CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE}") + STRING(REPLACE "${_remove_flags}" "${_linker_flags}" CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE}") + STRING(REPLACE "${_remove_flags}" "${_linker_flags}" CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY}") + STRING(REPLACE "${_remove_flags}" "${_linker_flags}" CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE}") + + # Unset temporary variables. + UNSET(_remove_flags) + UNSET(_linker_flags) +ENDIF(WIN32) +ENDMACRO(WIN32_IMAGE_VERSION_LINKER_FLAGS) diff --git a/cmake/platform.cmake b/cmake/platform.cmake new file mode 100644 index 0000000..befa871 --- /dev/null +++ b/cmake/platform.cmake @@ -0,0 +1,202 @@ +# Platform-specific functionality. + +# Hack to remove -rdynamic from CFLAGS and CXXFLAGS +# See http://public.kitware.com/pipermail/cmake/2006-July/010404.html +IF(CMAKE_SYSTEM_NAME STREQUAL "Linux") + SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS) + SET(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS) +ENDIF() + +# Don't embed rpaths in the executables. +SET(CMAKE_SKIP_RPATH ON) + +# stdint.h must be present. +INCLUDE(CheckIncludeFiles) +CHECK_INCLUDE_FILES(stdint.h HAVE_STDINT_H) +IF(NOT HAVE_STDINT_H) + MESSAGE(FATAL_ERROR "stdint.h is required.") +ENDIF(NOT HAVE_STDINT_H) + +# Common flag variables: +# [common] +# - RP_C_FLAGS_COMMON +# - RP_CXX_FLAGS_COMMON +# - RP_EXE_LINKER_FLAGS_COMMON +# - RP_SHARED_LINKER_FLAGS_COMMON +# - RP_MODULE_LINKER_FLAGS_COMMON +# [debug] +# - RP_C_FLAGS_DEBUG +# - RP_CXX_FLAGS_DEBUG +# - RP_EXE_LINKER_FLAGS_DEBUG +# - RP_SHARED_LINKER_FLAGS_DEBUG +# - RP_MODULE_LINKER_FLAGS_DEBUG +# [release] +# - RP_C_FLAGS_RELEASE +# - RP_CXX_FLAGS_RELEASE +# - RP_EXE_LINKER_FLAGS_RELEASE +# - RP_SHARED_LINKER_FLAGS_RELEASE +# - RP_MODULE_LINKER_FLAGS_RELEASE +# +# DEBUG and RELEASE variables do *not* include COMMON. +IF(MSVC) + INCLUDE(cmake/platform/msvc.cmake) +ELSE(MSVC) + INCLUDE(cmake/platform/gcc.cmake) +ENDIF(MSVC) + +# Platform-specific configuration. +IF(WIN32) + INCLUDE(cmake/platform/win32.cmake) +ENDIF(WIN32) + +# Check what flag is needed for stack smashing protection. +INCLUDE(CheckStackProtectorCompilerFlag) +CHECK_STACK_PROTECTOR_COMPILER_FLAG(RP_STACK_CFLAG) +SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${RP_STACK_CFLAG}") +SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${RP_STACK_CFLAG}") +UNSET(RP_STACK_CFLAG) + +# Check for Large File Support. +INCLUDE(CheckLargeFileSupport) +CHECK_LARGE_FILE_SUPPORT() +IF(NOT LFS_FOUND) + MESSAGE(FATAL_ERROR "Large File Support is required.") +ENDIF(NOT LFS_FOUND) +IF(LFS_DEFINITIONS) + SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${LFS_DEFINITIONS}") + SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${LFS_DEFINITIONS}") +ENDIF(LFS_DEFINITIONS) + +# Check for 64-bit time_t. +INCLUDE(Check64BitTimeSupport) +CHECK_64BIT_TIME_SUPPORT() +# NOTES: +# - glibc does not currently support 64-bit time_t on 32-bit. +# - Mac OS X does not (and won't) support 64-bit time_t on 32-bit. +IF(TIME64_DEFINITIONS) + SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${TIME64_DEFINITIONS}") + SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${TIME64_DEFINITIONS}") +ENDIF(TIME64_DEFINITIONS) + +# Set CMAKE flags. +# TODO: RelWithDebInfo / MinSizeRel? +# Common +SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${RP_C_FLAGS_COMMON}") +SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RP_CXX_FLAGS_COMMON}") +SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${RP_EXE_LINKER_FLAGS_COMMON}") +SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${RP_SHARED_LINKER_FLAGS_COMMON}") +SET(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${RP_MODULE_LINKER_FLAGS_COMMON}") +# Debug +SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${RP_C_FLAGS_DEBUG}") +SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${RP_CXX_FLAGS_DEBUG}") +SET(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} ${RP_EXE_LINKER_FLAGS_DEBUG}") +SET(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} ${RP_SHARED_LINKER_FLAGS_DEBUG}") +SET(CMAKE_MODULE_LINKER_FLAGS_DEBUG "${CMAKE_MODULE_LINKER_FLAGS_DEBUG} ${RP_MODULE_LINKER_FLAGS_DEBUG}") +# Release +SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${RP_C_FLAGS_RELEASE}") +SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${RP_CXX_FLAGS_RELEASE}") +SET(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} ${RP_EXE_LINKER_FLAGS_RELEASE}") +SET(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} ${RP_SHARED_LINKER_FLAGS_RELEASE}") +SET(CMAKE_MODULE_LINKER_FLAGS_RELEASE "${CMAKE_MODULE_LINKER_FLAGS_RELEASE} ${RP_MODULE_LINKER_FLAGS_RELEASE}") + +# Unset temporary variables. +# Common +UNSET(RP_C_FLAGS_COMMON) +UNSET(RP_CXX_FLAGS_COMMON) +UNSET(RP_EXE_LINKER_FLAGS_COMMON) +UNSET(RP_SHARED_LINKER_FLAGS_COMMON) +UNSET(RP_MODULE_LINKER_FLAGS_COMMON) +# Debug +UNSET(RP_C_FLAGS_DEBUG) +UNSET(RP_CXX_FLAGS_DEBUG) +UNSET(RP_EXE_LINKER_FLAGS_DEBUG) +UNSET(RP_SHARED_LINKER_FLAGS_DEBUG) +UNSET(RP_MODULE_LINKER_FLAGS_DEBUG) +# Release +UNSET(RP_C_FLAGS_RELEASE) +UNSET(RP_CXX_FLAGS_RELEASE) +UNSET(RP_EXE_LINKER_FLAGS_RELEASE) +UNSET(RP_SHARED_LINKER_FLAGS_RELEASE) +UNSET(RP_MODULE_LINKER_FLAGS_RELEASE) + +###### Windows-specific CMake functions. ###### + +# Set Windows subsystem when building with MSVC. +FUNCTION(SET_WINDOWS_SUBSYSTEM _target _subsystem) +IF(WIN32 AND MSVC) + GET_TARGET_PROPERTY(TARGET_LINK_FLAGS ${_target} LINK_FLAGS) + IF(TARGET_LINK_FLAGS) + SET(TARGET_LINK_FLAGS "${TARGET_LINK_FLAGS} ${RP_LINKER_FLAGS_${_subsystem}_EXE}") + ELSE() + SET(TARGET_LINK_FLAGS "${RP_LINKER_FLAGS_${_subsystem}_EXE}") + ENDIF() + SET_TARGET_PROPERTIES(${_target} PROPERTIES LINK_FLAGS "${TARGET_LINK_FLAGS}") +ENDIF(WIN32 AND MSVC) +ENDFUNCTION() + +# Disable automatic manifest generation when building with MSVC. +# Only use this if you have a custom manifest specified in the resource script. +FUNCTION(SET_WINDOWS_NO_MANIFEST _target) +IF(WIN32 AND MSVC) + GET_TARGET_PROPERTY(TARGET_LINK_FLAGS ${_target} LINK_FLAGS) + IF(TARGET_LINK_FLAGS) + SET(TARGET_LINK_FLAGS "${TARGET_LINK_FLAGS} /MANIFEST:NO") + ELSE() + SET(TARGET_LINK_FLAGS "/MANIFEST:NO") + ENDIF() + SET_TARGET_PROPERTIES(${_target} PROPERTIES LINK_FLAGS "${TARGET_LINK_FLAGS}") +ENDIF(WIN32 AND MSVC) +ENDFUNCTION() + +# Set Windows entrypoint. +# _target: Target. +# _entrypoint: Entry point. (main, wmain, WinMain, wWinMain) +# _setargv: If true, link to setargv.obj/wsetargv.obj in MSVC builds. +FUNCTION(SET_WINDOWS_ENTRYPOINT _target _entrypoint _setargv) +IF(WIN32) + IF(MSVC) + # MSVC automatically prepends an underscore if necessary. + SET(ENTRY_POINT_FLAG "/ENTRY:${_entrypoint}CRTStartup") + IF(_setargv) + IF(_entrypoint MATCHES ^wmain OR _entrypoint MATCHES ^wWinMain) + SET(SETARGV_FLAG "wsetargv.obj") + ELSE() + SET(SETARGV_FLAG "setargv.obj") + ENDIF() + ENDIF(_setargv) + UNSET(UNICODE_FLAG) + ELSE(MSVC) + # MinGW does not automatically prepend an underscore. + # TODO: Does ARM Windows have a leading underscore? + # TODO: _setargv for MinGW. + + # NOTE: MinGW uses separate crt*.o files for Unicode + # instead of a separate entry point. + IF(_entrypoint MATCHES "^w") + SET(UNICODE_FLAG "-municode") + STRING(SUBSTRING "${_entrypoint}" 1 -1 _entrypoint) + ENDIF() + + STRING(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" arch) + IF(arch MATCHES "^(i.|x)86$|^x86_64$|^amd64$") + IF(CMAKE_SIZEOF_VOID_P EQUAL 4) + SET(ENTRY_POINT "_${_entrypoint}CRTStartup") + ELSE() + SET(ENTRY_POINT "${_entrypoint}CRTStartup") + ENDIF() + ELSE() + SET(ENTRY_POINT "${_entrypoint}CRTStartup") + ENDIF(arch MATCHES "^(i.|x)86$|^x86_64$|^amd64$") + SET(ENTRY_POINT_FLAG "-Wl,-e,${ENTRY_POINT}") + UNSET(SETARGV_FLAG) + ENDIF(MSVC) + + GET_TARGET_PROPERTY(TARGET_LINK_FLAGS ${_target} LINK_FLAGS) + IF(TARGET_LINK_FLAGS) + SET(TARGET_LINK_FLAGS "${TARGET_LINK_FLAGS} ${UNICODE_FLAG} ${ENTRY_POINT_FLAG} ${SETARGV_FLAG}") + ELSE() + SET(TARGET_LINK_FLAGS "${UNICODE_FLAG} ${ENTRY_POINT_FLAG} ${SETARGV_FLAG}") + ENDIF() + SET_TARGET_PROPERTIES(${_target} PROPERTIES LINK_FLAGS "${TARGET_LINK_FLAGS}") +ENDIF(WIN32) +ENDFUNCTION() diff --git a/cmake/platform/gcc.cmake b/cmake/platform/gcc.cmake new file mode 100644 index 0000000..dfae13a --- /dev/null +++ b/cmake/platform/gcc.cmake @@ -0,0 +1,191 @@ +# gcc (and other Unix-like compilers, e.g. MinGW) +IF(CMAKE_CXX_COMPILER_ID MATCHES "(Apple)?[Cc]lang") + # FIXME: May need later than 2.9. + IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "2.9") + MESSAGE(FATAL_ERROR "clang-2.9 or later is required.") + ENDIF() +ELSEIF(CMAKE_COMPILER_IS_GNUCXX) + IF(CMAKE_CXX_COMPILER_VERSION VERSION_LESS "4.5") + MESSAGE(FATAL_ERROR "gcc-4.5 or later is required.") + ENDIF() +ENDIF() + +# Compiler flag modules. +INCLUDE(CheckCCompilerFlag) +INCLUDE(CheckCXXCompilerFlag) + +SET(RP_C_FLAGS_COMMON "-D_GNU_SOURCE=1") +SET(RP_CXX_FLAGS_COMMON "-D_GNU_SOURCE=1") +SET(RP_EXE_LINKER_FLAGS_COMMON "") + +UNSET(RP_C99_CFLAG) +UNSET(RP_CXX11_CXXFLAG) +UNSET(RP_CXX_NO_RTTI_CXXFLAG) +UNSET(RP_CXX_NO_EXCEPTIONS_CXXFLAG) +UNSET(RP_STACK_CFLAG) + +# Test for common CFLAGS and CXXFLAGS. +FOREACH(FLAG_TEST "-Wall" "-Wextra" "-fstrict-aliasing" "-Wno-multichar") + CHECK_C_COMPILER_FLAG("${FLAG_TEST}" CFLAG_${FLAG_TEST}) + IF(CFLAG_${FLAG_TEST}) + SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${FLAG_TEST}") + ENDIF(CFLAG_${FLAG_TEST}) + UNSET(CFLAG_${FLAG_TEST}) + + CHECK_CXX_COMPILER_FLAG("${FLAG_TEST}" CXXFLAG_${FLAG_TEST}) + IF(CXXFLAG_${FLAG_TEST}) + SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${FLAG_TEST}") + ENDIF(CXXFLAG_${FLAG_TEST}) + UNSET(CXXFLAG_${FLAG_TEST}) +ENDFOREACH() + +# Code coverage checking. +IF(ENABLE_COVERAGE) + # Partially based on: + # https://github.com/bilke/cmake-modules/blob/master/CodeCoverage.cmake + # (commit 59f8ab8dded56b490dec388ac6ad449318de8779) + IF("${CMAKE_CXX_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang") + # CMake 3.0.0 added code coverage support. + IF("${CMAKE_CXX_COMPILER_VERSION}" VERSION_LESS 3) + MESSAGE(FATAL_ERROR "clang-3.0.0 or later is required for code coverage testing.") + ENDIF() + ELSEIF(NOT CMAKE_COMPILER_IS_GNUCXX) + MESSAGE(FATAL_ERROR "Code coverage testing is currently only supported on gcc and clang.") + ENDIF() + + # Don't bother checking for the coverage options. + # We're assuming they're always supported. + SET(RP_C_FLAGS_COVERAGE "--coverage -fprofile-arcs -ftest-coverage") + SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${RP_C_FLAGS_COVERAGE}") + SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${RP_C_FLAGS_COVERAGE}") + + # Link gcov to all targets. + SET(GCOV_LIBRARY "-lgcov") + FOREACH(VAR "" C_ CXX_) + IF(CMAKE_${VAR}STANDARD_LIBRARIES) + SET(CMAKE_${VAR}STANDARD_LIBRARIES "${CMAKE_${VAR}STANDARD_LIBRARIES} ${GCOV_LIBRARY}") + ELSE(CMAKE_${VAR}STANDARD_LIBRARIES) + SET(CMAKE_${VAR}STANDARD_LIBRARIES "${GCOV_LIBRARY}") + ENDIF(CMAKE_${VAR}STANDARD_LIBRARIES) + ENDFOREACH(VAR) + + # Create a code coverage target. + FOREACH(_program gcov lcov genhtml) + FIND_PROGRAM(${_program}_PATH ${_program}) + IF(NOT ${_program}_PATH) + MESSAGE(FATAL_ERROR "${_program} not found; cannot enable code coverage testing.") + ENDIF(NOT ${_program}_PATH) + UNSET(${_program}_PATH) + ENDFOREACH(_program) + + ADD_CUSTOM_TARGET(coverage + WORKING_DIRECTORY "${CMAKE_BUILD_DIR}" + COMMAND ${POSIX_SH} "${CMAKE_SOURCE_DIR}/scripts/lcov.sh" "${CMAKE_BUILD_TYPE}" "rom-properties" "coverage" + ) +ENDIF(ENABLE_COVERAGE) + +# Test for common LDFLAGS. +# TODO: Doesn't work on OS X. (which means it's not really testing it!) +IF(NOT APPLE) + FOREACH(FLAG_TEST "-Wl,-O1" "-Wl,--sort-common" "-Wl,--as-needed" "-Wl,-Bsymbolic-functions") + CHECK_C_COMPILER_FLAG("${FLAG_TEST}" LDFLAG_${FLAG_TEST}) + IF(LDFLAG_${FLAG_TEST}) + SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} ${FLAG_TEST}") + ENDIF(LDFLAG_${FLAG_TEST}) + UNSET(LDFLAG_${FLAG_TEST}) + ENDFOREACH() + IF(NOT WIN32) + # Bsymbolic-functions doesn't make sense on Windows. + FOREACH(FLAG_TEST "-Wl,-Bsymbolic-functions") + CHECK_C_COMPILER_FLAG("${FLAG_TEST}" LDFLAG_${FLAG_TEST}) + IF(LDFLAG_${FLAG_TEST}) + SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} ${FLAG_TEST}") + ENDIF(LDFLAG_${FLAG_TEST}) + UNSET(LDFLAG_${FLAG_TEST}) + ENDFOREACH() + ENDIF(NOT WIN32) +ENDIF(NOT APPLE) +SET(RP_SHARED_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON}") +SET(RP_MODULE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON}") + +# Check for -Og. +# This flag was added in gcc-4.8, and enables optimizations that +# don't interfere with debugging. +CHECK_C_COMPILER_FLAG("-Og" CFLAG_OPTIMIZE_DEBUG) +IF (CFLAG_OPTIMIZE_DEBUG) + SET(CFLAG_OPTIMIZE_DEBUG "-Og") +ELSE(CFLAG_OPTIMIZE_DEBUG) + SET(CFLAG_OPTIMIZE_DEBUG "-O0") +ENDIF(CFLAG_OPTIMIZE_DEBUG) + +# Debug/release flags. +SET(RP_C_FLAGS_DEBUG "${CFLAG_OPTIMIZE_DEBUG} -ggdb -DDEBUG -D_DEBUG") +SET(RP_CXX_FLAGS_DEBUG "${CFLAG_OPTIMIZE_DEBUG} -ggdb -DDEBUG -D_DEBUG") +SET(RP_C_FLAGS_RELEASE "-O2 -ggdb -DNDEBUG") +SET(RP_CXX_FLAGS_RELEASE "-O2 -ggdb -DNDEBUG") + +# Unset temporary variables. +UNSET(CFLAG_OPTIMIZE_DEBUG) + +# Check for link-time optimization. (Release builds only.) +# FIXME: Running CMake with -DENABLE_LTO=ON, then -DENABLE_LTO=OFF +# doesn't seem to work right... (The flags aren't removed properly.) +# [Kubuntu 17.04, cmake-3.7.2] +IF(ENABLE_LTO) + # We need two wrappers in order for LTO to work properly: + # - gcc-ar: static library archiver + # - gcc-ranlib: static library indexer + # Without these wrappers, all sorts of undefined refernce errors + # occur in gcc-4.9 due to "slim" LTO objects, and possibly + # earlier versions for various reasons. + MESSAGE(STATUS "Checking if the gcc LTO wrappers are available:") + IF("${CMAKE_AR}" MATCHES "gcc-ar$") + # Already using the gcc-ar wrapper. + SET(GCC_WRAPPER_AR "${CMAKE_AR}") + ELSE() + # Replace ar with gcc-ar. + STRING(REGEX REPLACE "ar$" "gcc-ar" GCC_WRAPPER_AR "${CMAKE_AR}") + ENDIF() + IF("${CMAKE_RANLIB}" MATCHES "gcc-ranlib$") + # Already using the gcc-ranlib wrapper. + SET(GCC_WRAPPER_RANLIB "${CMAKE_RANLIB}") + ELSE() + # Replace ranlib with gcc-ranlib. + STRING(REGEX REPLACE "ranlib$" "gcc-ranlib" GCC_WRAPPER_RANLIB "${CMAKE_RANLIB}") + ENDIF() + + IF(EXISTS "${GCC_WRAPPER_AR}" AND EXISTS "${GCC_WRAPPER_RANLIB}") + # Found gcc binutils wrappers. + SET(CMAKE_AR "${GCC_WRAPPER_AR}") + SET(CMAKE_RANLIB "${GCC_WRAPPER_RANLIB}") + MESSAGE(STATUS "Checking if the gcc LTO wrappers are available: yes") + + # Check for the LTO compiler flag. + CHECK_C_COMPILER_FLAG("-flto" CFLAG_LTO) + IF(CFLAG_LTO) + SET(RP_C_FLAGS_RELEASE "${RP_C_FLAGS_RELEASE} -flto") + SET(RP_CXX_FLAGS_RELEASE "${RP_CXX_FLAGS_RELEASE} -flto") + SET(RP_EXE_LINKER_FLAGS_RELEASE "${RP_EXE_LINKER_FLAGS_RELEASE} -flto -fuse-linker-plugin") + SET(RP_SHARED_LINKER_FLAGS_RELEASE "${RP_SHARED_LINKER_FLAGS_RELEASE} -flto -fuse-linker-plugin") + SET(RP_MODULE_LINKER_FLAGS_RELEASE "${RP_MODULE_LINKER_FLAGS_RELEASE} -flto -fuse-linker-plugin") + ELSE(CFLAG_LTO) + MESSAGE(FATAL_ERROR "LTO optimization requested but -flto is not supported.") + ENDIF(CFLAG_LTO) + UNSET(CFLAG_LTO) + ELSE() + MESSAGE(STATUS "Checking if the gcc LTO wrappers are available: no") + MESSAGE(FATAL_ERROR "gcc binutils wrappers not found; cannot enable LTO.") + ENDIF() +ENDIF(ENABLE_LTO) + +# Use thin archives on Linux. +# References: +# - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=a5967db9af51a84f5e181600954714a9e4c69f1f +# - https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=9a6cfca4f4130444cb02536a4fdf7b6e285c713e +# - https://bugs.webkit.org/show_bug.cgi?id=108330 +IF(CMAKE_SYSTEM_NAME STREQUAL "Linux") + SET(CMAKE_C_ARCHIVE_CREATE " qcTP ") + SET(CMAKE_C_ARCHIVE_APPEND " qTP ") + SET(CMAKE_CXX_ARCHIVE_CREATE " qcTP ") + SET(CMAKE_CXX_ARCHIVE_APPEND " qTP ") +ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux") diff --git a/cmake/platform/msvc.cmake b/cmake/platform/msvc.cmake new file mode 100644 index 0000000..7c2fff3 --- /dev/null +++ b/cmake/platform/msvc.cmake @@ -0,0 +1,121 @@ +# Microsoft Visual C++ +IF(MSVC_VERSION LESS 1600) + MESSAGE(FATAL_ERROR "MSVC 2010 (10.0) or later is required.") +ENDIF() + +# Disable useless warnings: +# - MSVC "logo" messages +# - C4355: 'this' used in base member initializer list (used for Qt Dpointer pattern) +# - MSVCRT "deprecated" functions +# Increase some warnings to errors: +# - C4013: function undefined; this is allowed in C, but will +# probably cause a linker error. +SET(RP_C_FLAGS_COMMON "/nologo /wd4355 /wd4482 /we4013 -D_CRT_SECURE_NO_WARNINGS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE") +SET(RP_CXX_FLAGS_COMMON "${RP_C_FLAGS_COMMON}") +# NOTE: /TSAWARE is automatically set for Windows 2000 and later. (as of at least Visual Studio .NET 2003) +# NOTE 2: /TSAWARE is not applicable for DLLs. +SET(RP_EXE_LINKER_FLAGS_COMMON "/NOLOGO /DYNAMICBASE /NXCOMPAT /LARGEADDRESSAWARE") +SET(RP_SHARED_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON}") +SET(RP_MODULE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON}") + +# Test for "/sdl" and "/guard:cf". +INCLUDE(CheckCCompilerFlag) +FOREACH(FLAG_TEST "/sdl" "/guard:cf") + # CMake doesn't like certain characters in variable names. + STRING(REGEX REPLACE "/|:" "_" FLAG_TEST_VARNAME "${FLAG_TEST}") + + CHECK_C_COMPILER_FLAG("${FLAG_TEST}" CFLAG_${FLAG_TEST_VARNAME}) + IF(CFLAG_${FLAG_TEST_VARNAME}) + SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${FLAG_TEST}") + SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${FLAG_TEST}") + IF(FLAG_TEST STREQUAL "/guard:cf") + # "/guard:cf" must be added to linker flags as well. + SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} ${FLAG_TEST}") + SET(RP_SHARED_LINKER_FLAGS_COMMON "${RP_SHARED_LINKER_FLAGS_COMMON} ${FLAG_TEST}") + SET(RP_MODULE_LINKER_FLAGS_COMMON "${RP_MODULE_LINKER_FLAGS_COMMON} ${FLAG_TEST}") + ENDIF(FLAG_TEST STREQUAL "/guard:cf") + ENDIF(CFLAG_${FLAG_TEST_VARNAME}) + UNSET(CFLAG_${FLAG_TEST_VARNAME}) +ENDFOREACH() + +# Disable warning C4996 (deprecated), then re-enable it. +# Otherwise, it gets handled as an error due to /sdl. +SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} /wd4996 /w34996") +SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} /wd4996 /w34996") + +# MSVC 2015 uses thread-safe statics by default. +# This doesn't work on XP, so disable it. +IF(MSVC_VERSION GREATER 1899) + SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} /Zc:threadSafeInit-") + SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} /Zc:threadSafeInit-") +ENDIF() + +# Disable the RC and MASM "logo". +# FIXME: Setting CMAKE_RC_FLAGS causes msbuild to fail, +# since CMake already sets /NOLOGO there. +# - Also disabling /NOLOGO for MASM just in case. +#SET(CMAKE_RC_FLAGS "/NOLOGO") +#SET(CMAKE_ASM_MASM_FLAGS "/NOLOGO") + +# FIXME: MSVC 2015's 32-bit masm has problems when using msbuild: +# - The default /W3 fails for seemingly no reason. /W0 fixes it. +# - Compilation fails due to no SAFESEH handlers in inffas32.asm. +# NOTE: We're enabling these for all MSVC platforms, not just 32-bit. +# NOTE 2: We need to cache this in order to prevent random build failures +# caused by an empty string being cached instead. +SET(CMAKE_ASM_MASM_FLAGS "/W0 /safeseh" CACHE STRING + "Flags used by the assembler during all build types.") + +# CPU architecture. +STRING(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" arch) + +# Check if CMAKE_SIZEOF_VOID_P is set correctly. +IF(NOT CMAKE_SIZEOF_VOID_P) + # CMAKE_SIZEOF_VOID_P isn't set. + # Set it based on CMAKE_SYSTEM_PROCESSOR. + # FIXME: This won't work if we're cross-compiling, e.g. using + # the x86_amd64 or amd64_x86 toolchains. + IF(arch MATCHES "^x86_64$|^amd64$|^ia64$") + SET(CMAKE_SIZEOF_VOID_P 8) + ELSEIF(arch MATCHES "^(i.|x)86$") + SET(CMAKE_SIZEOF_VOID_P 4) + ELSE() + # Assume other CPUs are 32-bit. + SET(CMAKE_SIZEOF_VOID_P 4) + ENDIF() +ENDIF(NOT CMAKE_SIZEOF_VOID_P) + +# Use stdcall on i386. +# Applies to unexported functions only. +# Exported functions must have explicit calling conventions. +IF(arch MATCHES "^(i.|x)86$|^x86_64$|^amd64$|^ia64$" AND NOT CMAKE_CL_64) + SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} /Gz") + SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} /Gz") +ENDIF() +UNSET(arch) + +# TODO: Code coverage checking for MSVC? +IF(ENABLE_COVERAGE) + MESSAGE(FATAL_ERROR "Code coverage testing is currently only supported on gcc and clang.") +ENDIF(ENABLE_COVERAGE) + +# Debug/release flags. +SET(RP_C_FLAGS_DEBUG "/Zi") +SET(RP_CXX_FLAGS_DEBUG "/Zi") +SET(RP_EXE_LINKER_FLAGS_DEBUG "/DEBUG /INCREMENTAL") +SET(RP_SHARED_LINKER_FLAGS_DEBUG "${RP_EXE_LINKER_FLAGS_DEBUG}") +SET(RP_MODULE_LINKER_FLAGS_DEBUG "${RP_EXE_LINKER_FLAGS_DEBUG}") +SET(RP_C_FLAGS_RELEASE "/Zi") +SET(RP_CXX_FLAGS_RELEASE "/Zi") +SET(RP_EXE_LINKER_FLAGS_RELEASE "/DEBUG /INCREMENTAL:NO /OPT:ICF,REF") +SET(RP_SHARED_LINKER_FLAGS_RELEASE "${RP_EXE_LINKER_FLAGS_RELEASE}") +SET(RP_MODULE_LINKER_FLAGS_RELEASE "${RP_EXE_LINKER_FLAGS_RELEASE}") + +# Check for link-time optimization. (Release builds only.) +IF(ENABLE_LTO) + SET(RP_C_FLAGS_RELEASE "${RP_C_FLAGS_RELEASE} /GL") + SET(RP_CXX_FLAGS_RELEASE "${RP_CXX_FLAGS_RELEASE} /GL") + SET(RP_EXE_LINKER_FLAGS_RELEASE "${RP_EXE_LINKER_FLAGS_RELEASE} /LTCG") + SET(RP_SHARED_LINKER_FLAGS_RELEASE "${RP_SHARED_LINKER_FLAGS_RELEASE} /LTCG") + SET(RP_MODULE_LINKER_FLAGS_RELEASE "${RP_MODULE_LINKER_FLAGS_RELEASE} /LTCG") +ENDIF(ENABLE_LTO) diff --git a/cmake/platform/win32-gcc.cmake b/cmake/platform/win32-gcc.cmake new file mode 100644 index 0000000..bc2f239 --- /dev/null +++ b/cmake/platform/win32-gcc.cmake @@ -0,0 +1,105 @@ +# Win32-specific CFLAGS/CXXFLAGS. +# For MinGW compilers. + +# Enable "secure" API functions: *_s() +SET(RP_C_FLAGS_WIN32 "${RP_C_FLAGS_WIN32} -DMINGW_HAS_SECURE_API") + +# Subsystem and minimum Windows version: +# - If 32-bit: 5.01 +# - If 64-bit: 5.02 +# NOTE: MS_ENH_RSA_AES_PROV is only available starting with +# Windows XP. Because we're actually using some XP-specific +# functionality now, the minimum version is now Windows XP. +IF(CMAKE_SIZEOF_VOID_P EQUAL 8) + # 64-bit, Unicode Windows only. + # (There is no 64-bit ANSI Windows.) + SET(CMAKE_CREATE_WIN32_EXE "-Wl,--subsystem,windows:5.02") + SET(CMAKE_CREATE_CONSOLE_EXE "-Wl,--subsystem,console:5.02") +ELSE() + # 32-bit, Unicode Windows only. + SET(CMAKE_CREATE_WIN32_EXE "-Wl,--subsystem,windows:5.00") + SET(CMAKE_CREATE_CONSOLE_EXE "-Wl,--subsystem,console:5.00") +ENDIF() + +SET(RP_EXE_LINKER_FLAGS_WIN32 "") +SET(RP_SHARED_LINKER_FLAGS_WIN32 "") +SET(RP_MODULE_LINKER_FLAGS_WIN32 "") + +# Release build: Prefer static libraries. +IF(CMAKE_BUILD_TYPE MATCHES ^release) + SET(CMAKE_FIND_LIBRARY_SUFFIXES .lib .a ${CMAKE_FIND_LIBRARY_SUFFIXES}) +ENDIF(CMAKE_BUILD_TYPE MATCHES ^release) + +# Test for various linker flags. +# NOTE: --tsaware is only valid for EXEs, not DLLs. +# TODO: Make static linkage a CMake option: --static-libgcc, --static-libstdc++ +FOREACH(FLAG_TEST "-Wl,--large-address-aware" "-Wl,--nxcompat" "-Wl,--tsaware") + # CMake doesn't like "+" characters in variable names. + STRING(REPLACE "+" "_" FLAG_TEST_VARNAME "${FLAG_TEST}") + + IF(LDFLAG_${FLAG_TEST_VARNAME}) + SET(RP_EXE_LINKER_FLAGS_WIN32 "${RP_EXE_LINKER_FLAGS_WIN32} ${FLAG_TEST}") + ENDIF(LDFLAG_${FLAG_TEST_VARNAME}) + UNSET(LDFLAG_${FLAG_TEST_VARNAME}) + UNSET(FLAG_TEST_VARNAME) +ENDFOREACH() +SET(RP_SHARED_LINKER_FLAGS_WIN32 "${RP_EXE_LINKER_FLAGS_WIN32}") +SET(RP_MODULE_LINKER_FLAGS_WIN32 "${RP_EXE_LINKER_FLAGS_WIN32}") + +# EXE-only flags. +FOREACH(FLAG_TEST "-Wl,--tsaware") + # CMake doesn't like "+" characters in variable names. + STRING(REPLACE "+" "_" FLAG_TEST_VARNAME "${FLAG_TEST}") + + IF(LDFLAG_${FLAG_TEST_VARNAME}) + SET(RP_EXE_LINKER_FLAGS_WIN32 "${RP_EXE_LINKER_FLAGS_WIN32} ${FLAG_TEST}") + ENDIF(LDFLAG_${FLAG_TEST_VARNAME}) + UNSET(LDFLAG_${FLAG_TEST_VARNAME}) + UNSET(FLAG_TEST_VARNAME) +ENDFOREACH() + +# Test for dynamicbase (ASLR) support. +# Simply enabling --dynamicbase won't work; we also need to +# tell `ld` to generate the .reloc section. Also, there's +# a bug in `ld` where if it generates the .reloc section, +# it conveniently forgets the entry point. +# Reference: https://lists.libav.org/pipermail/libav-devel/2014-October/063871.html +# NOTE: Entry point is set using SET_WINDOWS_ENTRYPOINT() +# in platform.cmake due to ANSI/Unicode differences. +FOREACH(FLAG_TEST "-Wl,--dynamicbase,--pic-executable") + # CMake doesn't like "+" characters in variable names. + STRING(REPLACE "+" "_" FLAG_TEST_VARNAME "${FLAG_TEST}") + + CHECK_C_COMPILER_FLAG("${FLAG_TEST}" LDFLAG_${FLAG_TEST_VARNAME}) + IF(LDFLAG_${FLAG_TEST_VARNAME}) + # Entry point is only set for EXEs. + # GNU `ld` always has the -e option. + SET(RP_EXE_LINKER_FLAGS_WIN32 "${RP_EXE_LINKER_FLAGS_WIN32} ${FLAG_TEST}") + ENDIF(LDFLAG_${FLAG_TEST_VARNAME}) + UNSET(LDFLAG_${FLAG_TEST_VARNAME}) + UNSET(FLAG_TEST_VARNAME) +ENDFOREACH() + +# Enable windres support on MinGW. +# http://www.cmake.org/Bug/view.php?id=4068 +SET(CMAKE_RC_COMPILER_INIT windres) +ENABLE_LANGUAGE(RC) + +# NOTE: Setting CMAKE_RC_OUTPUT_EXTENSION doesn't seem to work. +# Force windres to output COFF, even though it'll use the .res extension. +SET(CMAKE_RC_OUTPUT_EXTENSION .obj) +SET(CMAKE_RC_COMPILE_OBJECT + " --output-format=coff -o ") + +# Append the CFLAGS and LDFLAGS. +SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${RP_C_FLAGS_WIN32}") +SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${RP_C_FLAGS_WIN32} ${RP_CXX_FLAGS_WIN32}") +SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} ${RP_EXE_LINKER_FLAGS_WIN32}") +SET(RP_SHARED_LINKER_FLAGS_COMMON "${RP_SHARED_LINKER_FLAGS_COMMON} ${RP_SHARED_LINKER_FLAGS_WIN32}") +SET(RP_MODULE_LINKER_FLAGS_COMMON "${RP_MODULE_LINKER_FLAGS_COMMON} ${RP_MODULE_LINKER_FLAGS_WIN32}") + +# Unset temporary variables. +UNSET(RP_C_FLAGS_WIN32) +UNSET(RP_EXE_LINKER_FLAGS_WIN32) +UNSET(RP_SHARED_LINKER_FLAGS_WIN32) +UNSET(RP_MODULE_LINKER_FLAGS_WIN32) diff --git a/cmake/platform/win32-msvc.cmake b/cmake/platform/win32-msvc.cmake new file mode 100644 index 0000000..1dc2ddc --- /dev/null +++ b/cmake/platform/win32-msvc.cmake @@ -0,0 +1,64 @@ +# Win32-specific CFLAGS/CXXFLAGS. +# For Microsoft Visual C++ compilers. + +# Basic platform flags for MSVC: +# - wchar_t should be a distinct type. (MSVC 2002+) +IF(MSVC_VERSION GREATER 1200) + SET(RP_C_FLAGS_WIN32 "${RP_C_FLAGS_WIN32} /Zc:wchar_t") +ENDIF() + +# NOTE: This program is Unicode only on Windows. +# No ANSI support. + +# Subsystem and minimum Windows version: +# - If 32-bit: 5.00 +# - If 64-bit: 5.02 +# ROM Properties does NOT support ANSI Windows. +# MSVC 2010's minimum supported target OS is XP SP2. +# MSVC 2012 and later has a minimum subsystem value of 5.01. +# NOTE: CMake sets /subsystem:windows or /subsystem:console itself, +# but with the MSBUILD generator, that's *before* this one, which +# results in console programs being linked as Windows. +# Use the SET_WINDOWS_SUBSYSTEM(_target _subsystem) function defined in +# platform.cmake. That macro will only do anything if building with +# MSVC, since the variables won't be defined anywhere else. +# NOTE: MS_ENH_RSA_AES_PROV is only available starting with +# Windows XP. Because we're actually using some XP-specific +# functionality now, the minimum version is now Windows XP. +IF(MSVC AND CMAKE_CL_64) + # 64-bit, Unicode Windows only. (MSVC) + # (There is no 64-bit ANSI Windows.) + # Minimum target version is Windows Server 2003 / XP 64-bit. + SET(RP_WIN32_SUBSYSTEM_VERSION "5.02") +ELSEIF(NOT MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8) + # 64-bit, Unicode Windows only. (MinGW) + # (There is no 64-bit ANSI Windows.) + # Minimum target version is Windows Server 2003 / XP 64-bit. + SET(RP_WIN32_SUBSYSTEM_VERSION "5.02") +ELSE() + # 32-bit, Unicode Windows only. + IF(MSVC_VERSION GREATER 1600) + # MSVC 2012 or later. + # Minimum target version is Windows XP. + SET(MCRECOVER_LINKER_FLAGS_WIN32_EXE "/SUBSYSTEM:WINDOWS,5.01") + SET(MCRECOVER_LINKER_FLAGS_CONSOLE_EXE "/SUBSYSTEM:CONSOLE,5.01") + ELSE() + # MSVC 2010 or earlier. + SET(MCRECOVER_LINKER_FLAGS_WIN32_EXE "/SUBSYSTEM:WINDOWS,5.00") + SET(MCRECOVER_LINKER_FLAGS_CONSOLE_EXE "/SUBSYSTEM:CONSOLE,5.00") + ENDIF() +ENDIF() +SET(RP_LINKER_FLAGS_WIN32_EXE "/SUBSYSTEM:WINDOWS,${RP_WIN32_SUBSYSTEM_VERSION}") +SET(RP_LINKER_FLAGS_CONSOLE_EXE "/SUBSYSTEM:CONSOLE,${RP_WIN32_SUBSYSTEM_VERSION}") +UNSET(RP_WIN32_SUBSYSTEM_VERSION) + +# Append the CFLAGS and LDFLAGS. +SET(RP_C_FLAGS_COMMON "${RP_C_FLAGS_COMMON} ${RP_C_FLAGS_WIN32}") +SET(RP_CXX_FLAGS_COMMON "${RP_CXX_FLAGS_COMMON} ${RP_C_FLAGS_WIN32} ${RP_CXX_FLAGS_WIN32}") +SET(RP_EXE_LINKER_FLAGS_COMMON "${RP_EXE_LINKER_FLAGS_COMMON} ${RP_EXE_LINKER_FLAGS_WIN32}") +SET(RP_SHARED_LINKER_FLAGS_COMMON "${RP_SHARED_LINKER_FLAGS_COMMON} ${RP_EXE_LINKER_FLAGS_WIN32}") +SET(RP_MODULE_LINKER_FLAGS_COMMON "${RP_MODULE_LINKER_FLAGS_COMMON} ${RP_EXE_LINKER_FLAGS_WIN32}") + +# Unset temporary variables. +UNSET(RP_C_FLAGS_WIN32) +UNSET(RP_EXE_LINKER_FLAGS_WIN32) diff --git a/cmake/platform/win32.cmake b/cmake/platform/win32.cmake new file mode 100644 index 0000000..901c056 --- /dev/null +++ b/cmake/platform/win32.cmake @@ -0,0 +1,44 @@ +# Win32-specific CFLAGS/CXXFLAGS. + +# Basic platform flags: +# - Enable strict type checking in the Windows headers. +# - Define WIN32_LEAN_AND_MEAN to reduce the number of Windows headers included. +# - Define NOMINMAX to disable the MIN() and MAX() macros. +SET(RP_C_FLAGS_WIN32 "-DSTRICT -DWIN32_LEAN_AND_MEAN -DNOMINMAX") + +# NOTE: This program only supports Unicode on Windows. +# No support for ANSI Windows, i.e. Win9x. +SET(RP_C_FLAGS_WIN32 "${RP_C_FLAGS_WIN32} -DUNICODE -D_UNICODE") + +# Minimum Windows version for the SDK is Windows XP. +SET(RP_C_FLAGS_WIN32 "${RP_C_FLAGS_WIN32} -DWINVER=0x0501 -D_WIN32_WINNT=0x0501 -D_WIN32_IE=0x0600") + +# Enable secure template overloads for C++. +# References: +# - MinGW's _mingw_secapi.h +# - http://msdn.microsoft.com/en-us/library/ms175759%28v=VS.100%29.aspx +SET(RP_CXX_FLAGS_WIN32 "-D_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES=1") +SET(RP_CXX_FLAGS_WIN32 "${RP_CXX_FLAGS_WIN32} -D_CRT_SECURE_CPP_OVERLOAD_SECURE_NAMES_MEMORY=1") +SET(RP_CXX_FLAGS_WIN32 "${RP_CXX_FLAGS_WIN32} -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1") +SET(RP_CXX_FLAGS_WIN32 "${RP_CXX_FLAGS_WIN32} -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1") +SET(RP_CXX_FLAGS_WIN32 "${RP_CXX_FLAGS_WIN32} -D_CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_MEMORY=1") + +# Determine the processorArchitecture for the manifest files. +STRING(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" arch) +IF(arch MATCHES "^x86_64$|^amd64$") + SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "amd64") +ELSEIF(arch MATCHES "^ia64$") + SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "ia64") +ELSEIF(arch MATCHES "^(i.|x)86$") + SET(WIN32_MANIFEST_PROCESSOR_ARCHITECTURE "x86") +ELSE() + MESSAGE(FATAL_ERROR "Unsupported CPU architecture, please fix!") +ENDIF() +UNSET(arch) + +# Compiler-specific Win32 flags. +IF(MSVC) + INCLUDE(cmake/platform/win32-msvc.cmake) +ELSE(MSVC) + INCLUDE(cmake/platform/win32-gcc.cmake) +ENDIF(MSVC) diff --git a/git_version.sh b/git_version.sh new file mode 100755 index 0000000..b41641b --- /dev/null +++ b/git_version.sh @@ -0,0 +1,373 @@ +#!/bin/sh +# +# Generate some basic versioning information which can be piped to a header. +# +# Copyright (c) 2006-2007 Luc Verhaegen +# Copyright (C) 2007-2008 Hans Ulrich Niedermann +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. +# +# This script is based on the one written for xf86-video-unichrome by +# Luc Verhaegen, but was rewritten almost completely by Hans Ulrich +# Niedermann. The script contains a few bug fixes from Egbert Eich, +# Matthias Hopf, Joerg Sonnenberger, and possibly others. +# +# The author thanks the nice people on #git for the assistance. +# +# Simple testing of this script: +# /sbin/busybox sh git_version.sh --example > moo.c \ +# && gcc -Wall -Wextra -Wno-unused -o moo moo.c \ +# && ./moo +# (bash should also do) +# +# For how to hook this up to your automake- and/or imake-based build +# system, best take a look at how the RadeonHD.am and/or RadeonHD.tmpl +# work in the xf86-video-radeonhd build system. For non-recursive make, +# you can probably make things a little bit simpler. +# +# Requires git >= 1.3.0 for the 'git foo' (with space) syntax, +# and git >= 1.4 for some specific commands. + +# Help messages +USAGE="[