Skip to content

Commit

Permalink
Squashed 'cmake_modules/yacma/' content from commit e50bcb9
Browse files Browse the repository at this point in the history
git-subtree-dir: cmake_modules/yacma
git-subtree-split: e50bcb9a4f6c9114df78050ec0c3e7806f773e1a
  • Loading branch information
bluescarni committed Oct 21, 2019
0 parents commit 1cc29f9
Show file tree
Hide file tree
Showing 5 changed files with 422 additions and 0 deletions.
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2016-2019 Francesco Biscani

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
AUTHORS OR COPYRIGHT HOLDERS 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.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# yacma

Yet another CMake modules archive.
188 changes: 188 additions & 0 deletions YACMACompilerLinkerSettings.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
if(_YACMACompilerLinkerSettingsIncluded)
return()
endif()

include(CheckCXXCompilerFlag)

# NOTE: we want to make sure the following variables are defined each time we include
# this file, even when the file is re-included (e.g., from a parallel unrelated tree).

# Clang detection:
# http://stackoverflow.com/questions/10046114/in-cmake-how-can-i-test-if-the-compiler-is-clang
# http://www.cmake.org/cmake/help/v2.8.10/cmake.html#variable:CMAKE_LANG_COMPILER_ID
# NOTE: we use MATCHES here because on OSX sometimes the compiler calls itself "AppleClang".
if(${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
set(YACMA_COMPILER_IS_CLANGXX TRUE)
endif()

if(${CMAKE_CXX_COMPILER_ID} MATCHES "Intel")
set(YACMA_COMPILER_IS_INTELXX TRUE)
endif()

if(MSVC)
set(YACMA_COMPILER_IS_MSVC TRUE)
endif()

if(CMAKE_COMPILER_IS_GNUCXX)
set(YACMA_COMPILER_IS_GNUCXX TRUE)
endif()

# Detect the hcc compiler.
if(YACMA_COMPILER_IS_CLANGXX AND "${CMAKE_CXX_COMPILER}" MATCHES "hcc")
set(YACMA_COMPILER_IS_HCC TRUE)
endif()

# This is an OS X specific setting that is suggested to be enabled. See:
# https://blog.kitware.com/upcoming-in-cmake-2-8-12-osx-rpath-support/
# http://stackoverflow.com/questions/31561309/cmake-warnings-under-os-x-macosx-rpath-is-not-specified-for-the-following-targe
if(APPLE)
message(STATUS "OSX detected, setting the 'CMAKE_MACOSX_RPATH' option to TRUE.")
set(CMAKE_MACOSX_RPATH TRUE)
endif()

# Helper function to print out the autodetected flags.
function(_YACMA_REPORT_FLAGS)
message(STATUS "The C++ compiler ID is: ${CMAKE_CXX_COMPILER_ID}")
message(STATUS "YACMA autodetected C++ flags: ${YACMA_CXX_FLAGS}")
message(STATUS "YACMA autodetected C++ debug flags: ${YACMA_CXX_FLAGS_DEBUG}")
endfunction()

# Enable conditionally a CXX flag, if supported by the compiler.
# This is for flags intended to be enabled in all configurations.
# NOTE: we use macros and go through temporary private variables
# because it's apparently impossible to append to an internal
# CACHEd list.
macro(_YACMA_CHECK_ENABLE_CXX_FLAG flag)
set(CMAKE_REQUIRED_QUIET TRUE)
check_cxx_compiler_flag("${flag}" YACMA_CHECK_CXX_FLAG)
unset(CMAKE_REQUIRED_QUIET)
if(YACMA_CHECK_CXX_FLAG)
message(STATUS "'${flag}': flag is supported by the compiler, enabling.")
list(APPEND _YACMA_CXX_FLAGS "${flag}")
else()
message(STATUS "'${flag}': flag is not supported by the compiler.")
endif()
# NOTE: check_cxx_compiler stores variables in the cache.
unset(YACMA_CHECK_CXX_FLAG CACHE)
endmacro()

# Enable conditionally a debug CXX flag, is supported by the compiler.
# This is for flags intended to be enabled in debug mode.
macro(_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG flag)
set(CMAKE_REQUIRED_QUIET TRUE)
check_cxx_compiler_flag("${flag}" YACMA_CHECK_DEBUG_CXX_FLAG)
unset(CMAKE_REQUIRED_QUIET)
if(YACMA_CHECK_DEBUG_CXX_FLAG)
message(STATUS "'${flag}': debug flag is supported by the compiler, enabling.")
list(APPEND _YACMA_CXX_FLAGS_DEBUG "${flag}")
else()
message(STATUS "'${flag}': debug flag is not supported by the compiler.")
endif()
unset(YACMA_CHECK_DEBUG_CXX_FLAG CACHE)
endmacro()

# What we want to avoid is to re-run the expensive flag checks. We will set cache variables
# on the initial run and skip following CMake runs.
if(NOT _YACMACompilerLinkerSettingsRun)
# Init the flags lists.
set(_YACMA_CXX_FLAGS "")
set(_YACMA_CXX_FLAGS_DEBUG "")

# Configuration bits specific for GCC.
if(YACMA_COMPILER_IS_GNUCXX)
_YACMA_CHECK_ENABLE_CXX_FLAG(-fdiagnostics-color=auto)
endif()

# Configuration bits specific for clang.
if(YACMA_COMPILER_IS_CLANGXX)
# For now it seems like -Wshadow from clang behaves better than GCC's, just enable it here
# for the time being.
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wshadow)
# Clang is better at this flag than GCC.
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Werror)
endif()

# Common configuration for GCC, clang and Intel.
if(YACMA_COMPILER_IS_CLANGXX OR YACMA_COMPILER_IS_INTELXX OR YACMA_COMPILER_IS_GNUCXX)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wall)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wextra)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wnon-virtual-dtor)
# NOTE: this flag is a bit too chatty, let's disable it for the moment.
#_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wnoexcept)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wlogical-op)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wconversion)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wdeprecated)
# This limit is supposed to be at least 1024 in C++11, but for some reason
# clang sets this to 256, and gcc to 900.
_YACMA_CHECK_ENABLE_CXX_FLAG(-ftemplate-depth=1024)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wold-style-cast)
# NOTE: disable this for now, as it results in a lot of clutter from Boost.
# _YACMA_CHECK_ENABLE_CXX_FLAG(-Wzero-as-null-pointer-constant)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-pedantic-errors)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wdisabled-optimization)
# This is useful when the compiler decides the template backtrace is too verbose.
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-ftemplate-backtrace-limit=0)
if(YACMA_COMPILER_IS_HCC)
message(STATUS "hcc compiler detected, the '-fstack-protector-all' flag will not be enabled.")
else()
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-fstack-protector-all)
endif()
# A few suggestion flags.
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wsuggest-attribute=pure)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wsuggest-attribute=const)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wsuggest-attribute=noreturn)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wsuggest-attribute=format)
# From GCC 5.
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wodr)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wsuggest-final-types)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wsuggest-final-methods)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wsuggest-override)
# From GCC 6.
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wshift-negative-value)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wshift-overflow=2)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wduplicated-cond)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wnull-dereference)
# From GCC 7.
#_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wduplicated-branches)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wrestrict)
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Waligned-new)
# From GCC 8.
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wcast-align=strict)
# This is supposed to produce a nice graphical visualization
# of mismatching template errors.
_YACMA_CHECK_ENABLE_CXX_FLAG(-fdiagnostics-show-template-tree)
if(YACMA_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "5.999")
# NOTE: GCC >= 6 seems to be wrongly warning about visibility attributes
# in some situations:
# https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80947
# Let's just disable the warning for now.
message(STATUS "Activating the '-Wno-attributes' workaround for GCC >= 6.")
_YACMA_CHECK_ENABLE_CXX_FLAG(-Wno-attributes)
endif()
if(YACMA_COMPILER_IS_GNUCXX)
# The -Wmaybe-uninitialized flag is enabled by -Wall, but it is known
# to emit a lot of possibly spurious warnings. Let's just disable it.
message(STATUS "Activating the '-Wno-maybe-uninitialized' workaround for GCC.")
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(-Wno-maybe-uninitialized)
endif()
endif()

# MSVC setup.
if(YACMA_COMPILER_IS_MSVC AND NOT YACMA_COMPILER_IS_CLANGXX)
# Enable higher warning level than usual.
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(/W4)
# Treat warnings as errors.
_YACMA_CHECK_ENABLE_DEBUG_CXX_FLAG(/WX)
endif()

# Set the cache variables.
set(YACMA_CXX_FLAGS "${_YACMA_CXX_FLAGS}" CACHE INTERNAL "")
set(YACMA_CXX_FLAGS_DEBUG "${_YACMA_CXX_FLAGS_DEBUG}" CACHE INTERNAL "")
set(_YACMACompilerLinkerSettingsRun YES CACHE INTERNAL "")
endif()

# Final report.
_YACMA_REPORT_FLAGS()

# Mark as included.
set(_YACMACompilerLinkerSettingsIncluded YES)
150 changes: 150 additions & 0 deletions YACMAPythonSetup.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
if(YACMAPythonSetupIncluded)
return()
endif()

# NOTE: this is a heuristic to determine whether we need to link to the Python library.
# In theory, Python extensions don't need to, as they are dlopened() by the Python process
# and thus they don't need to be linked to the Python library at compile time. However,
# the dependency on Boost.Python muddies the waters, as BP itself does link to the Python
# library, at least on some platforms. The following configuration seems to be working fine
# on various CI setups.
if(WIN32)
message(STATUS "Python modules require linking to the Python library.")
set(_YACMA_PYTHON_MODULE_NEED_LINK TRUE)
else()
message(STATUS "Python modules do NOT require linking to the Python library.")
set(_YACMA_PYTHON_MODULE_NEED_LINK FALSE)
endif()

# Find Python interpreter.
find_package(PythonInterp REQUIRED)

if(_YACMA_PYTHON_MODULE_NEED_LINK)
# NOTE: this will give us both the Python lib and the Python include dir.
find_package(PythonLibs REQUIRED)
if(NOT YACMA_PYTHON_INCLUDE_DIR)
set(YACMA_PYTHON_INCLUDE_DIR "${PYTHON_INCLUDE_DIRS}" CACHE PATH "Path to the Python include dir.")
endif()
else()
# NOTE: we need to determine the include dir on our own.
if(NOT YACMA_PYTHON_INCLUDE_DIR)
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from __future__ import print_function\nfrom distutils import sysconfig\nprint(sysconfig.get_python_inc())"
OUTPUT_VARIABLE _YACMA_PYTHON_INCLUDE_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
if(_YACMA_PYTHON_INCLUDE_DIR)
set(YACMA_PYTHON_INCLUDE_DIR "${_YACMA_PYTHON_INCLUDE_DIR}" CACHE PATH "Path to the Python include dir.")
endif()
endif()
if(NOT YACMA_PYTHON_INCLUDE_DIR)
message(FATAL_ERROR "Could not determine the Python include dir.")
endif()
endif()
mark_as_advanced(YACMA_PYTHON_INCLUDE_DIR)

message(STATUS "Python interpreter: ${PYTHON_EXECUTABLE}")
message(STATUS "Python interpreter version: ${PYTHON_VERSION_STRING}")
if(_YACMA_PYTHON_MODULE_NEED_LINK)
message(STATUS "Python libraries: ${PYTHON_LIBRARIES}")
endif()
message(STATUS "Python include dir: ${YACMA_PYTHON_INCLUDE_DIR}")

# An imported target to be used when building extension modules.
if(_YACMA_PYTHON_MODULE_NEED_LINK)
add_library(YACMA::PythonModule UNKNOWN IMPORTED)
set_target_properties(YACMA::PythonModule PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${YACMA_PYTHON_INCLUDE_DIR}"
IMPORTED_LOCATION "${PYTHON_LIBRARIES}" IMPORTED_LINK_INTERFACE_LANGUAGES "C")
else()
add_library(YACMA::PythonModule INTERFACE IMPORTED)
set_target_properties(YACMA::PythonModule PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${YACMA_PYTHON_INCLUDE_DIR}")
endif()

# This flag is used to signal the need to override the default extension of the Python modules
# depending on the architecture. Under Windows, for instance, CMake produces shared objects as
# .dll files, but Python from 2.5 onwards requires .pyd files (hence the need to override).
set(_YACMA_PY_MODULE_EXTENSION "")

# Platform-specific setup.
if(UNIX)
if(APPLE)
message(STATUS "OS X platform detected.")
# Apparently on OS X Python expects the .so extension for compiled modules.
message(STATUS "Output extension for compiled modules will be '.so'.")
set(_YACMA_PY_MODULE_EXTENSION "so")
else()
message(STATUS "Generic UNIX platform detected.")
endif()
if(NOT YACMA_PYTHON_MODULES_INSTALL_PATH)
# NOTE: here we use this contraption (instead of the simple method below for Win32) because like this we can
# support installation into the CMake prefix (e.g., in the user's home dir).
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from __future__ import print_function\nimport distutils.sysconfig\nimport os\nprint(os.path.split(distutils.sysconfig.get_python_lib())[-1])"
OUTPUT_VARIABLE _YACMA_PY_PACKAGES_DIR OUTPUT_STRIP_TRAILING_WHITESPACE)
message(STATUS "Python packages dir is: ${_YACMA_PY_PACKAGES_DIR}")
set(YACMA_PYTHON_MODULES_INSTALL_PATH "lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/${_YACMA_PY_PACKAGES_DIR}" CACHE PATH "Install path for Python modules.")
mark_as_advanced(YACMA_PYTHON_MODULES_INSTALL_PATH)
endif()
elseif(WIN32)
message(STATUS "Windows platform detected.")
message(STATUS "Output extension for compiled modules will be '.pyd'.")
set(_YACMA_PY_MODULE_EXTENSION "pyd")
if(NOT YACMA_PYTHON_MODULES_INSTALL_PATH)
# On Windows, we will install directly into the install path of the Python interpreter.
execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())"
OUTPUT_VARIABLE _YACMA_PYTHON_MODULES_INSTALL_PATH OUTPUT_STRIP_TRAILING_WHITESPACE)
set(YACMA_PYTHON_MODULES_INSTALL_PATH "${_YACMA_PYTHON_MODULES_INSTALL_PATH}" CACHE PATH "Install path for Python modules.")
mark_as_advanced(YACMA_PYTHON_MODULES_INSTALL_PATH)
endif()
else()
message(FATAL_ERROR "Platform not supported.")
endif()

# Check the install path was actually detected.
if("${YACMA_PYTHON_MODULES_INSTALL_PATH}" STREQUAL "")
message(FATAL_ERROR "Python module install path not detected correctly.")
endif()

message(STATUS "Python modules install path: ${YACMA_PYTHON_MODULES_INSTALL_PATH}")

function(YACMA_PYTHON_MODULE name)
message(STATUS "Setting up the compilation of the Python module '${name}'.")
# If we need an explicit link to the Python library, we compile it as a normal shared library.
# Otherwise, we compile it as a module.
if(_YACMA_PYTHON_MODULE_NEED_LINK)
add_library("${name}" SHARED ${ARGN})
else()
add_library("${name}" MODULE ${ARGN})
endif()
# Any "lib" prefix normally added by CMake must be removed.
set_target_properties("${name}" PROPERTIES PREFIX "")
if(NOT ${_YACMA_PY_MODULE_EXTENSION} STREQUAL "")
# If needed, set a custom extension for the module.
message(STATUS "Setting up custom extension '${_YACMA_PY_MODULE_EXTENSION}' for the Python module '${name}'.")
set_target_properties("${name}" PROPERTIES SUFFIX ".${_YACMA_PY_MODULE_EXTENSION}")
endif()
# We need extra flags to be set when compiling Python modules, at least
# with clang and gcc. See:
# https://bugs.python.org/issue11149
# http://www.python.org/dev/peps/pep-3123/
# NOTE: not sure here how we should set flags up for MSVC or clang on windows, need
# to check in the future.
# NOTE: do not use the yacma compiler linker settings bits, so this module
# can be used stand-alone.
if(CMAKE_COMPILER_IS_GNUCXX OR ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
message(STATUS "Setting up extra compiler flag '-fwrapv' for the Python module '${name}'.")
target_compile_options(${name} PRIVATE "-fwrapv")
if(${PYTHON_VERSION_MAJOR} LESS 3)
message(STATUS "Python < 3 detected, setting up extra compiler flag '-fno-strict-aliasing' for the Python module '${name}'.")
target_compile_options(${name} PRIVATE "-fno-strict-aliasing")
endif()
endif()
if(APPLE AND ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang")
# On OSX + Clang this link flag is apparently necessary in order to avoid
# undefined references to symbols defined in the Python library. See also:
# https://github.com/potassco/clingo/issues/79
# https://stackoverflow.com/questions/25421479/clang-and-undefined-symbols-when-building-a-library
# https://cmake.org/pipermail/cmake/2017-March/065115.html
set_target_properties(${name} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup")
endif()
target_link_libraries("${name}" PRIVATE YACMA::PythonModule)
endfunction()

# Mark as included.
set(YACMAPythonSetupIncluded YES)
Loading

0 comments on commit 1cc29f9

Please sign in to comment.