Add graph references

This commit is contained in:
Abdelrahman Said
2026-06-28 13:49:01 +01:00
parent 0a9807e448
commit a11edf0c53
2578 changed files with 868045 additions and 0 deletions
@@ -0,0 +1,12 @@
# Taken from https://blog.kitware.com/cmake-and-the-default-build-type/
# Set the default build type to "Release"
set(default_build_type "Release")
get_property(isMultiConfig GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(NOT isMultiConfig AND NOT CMAKE_BUILD_TYPE)
message(STATUS "Setting build type to '${default_build_type}' as none was specified.")
set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE STRING "Choose the type of build." FORCE)
# Set the possible values of build type for cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo")
endif()
@@ -0,0 +1,36 @@
include(CheckCSourceCompiles)
include(CMakePushCheckState)
macro(check_tls_support VAR)
if(NOT DEFINED "${VAR}")
cmake_push_check_state()
set(CMAKE_REQUIRED_QUIET 1)
check_c_source_compiles("
__thread int tls;
int main(void) {
return 0;
}" HAVE_GCC_TLS)
if(HAVE_GCC_TLS)
message(STATUS "Thread-local storage: supported (__thread)")
set(${VAR} "__thread" CACHE INTERNAL "Thread-local storage support keyword in compiler")
else()
check_c_source_compiles("
__declspec(thread) int tls;
int main(void) {
return 0;
}" HAVE_MSVC_TLS)
if(HAVE_MSVC_TLS)
message(STATUS "Thread-local storage: supported (__declspec(thread))")
set(${VAR} "__declspec(thread)" CACHE INTERNAL "Thread-local storage keyword in compiler")
else()
message(STATUS "Thread-local storage: not supported")
set(${VAR} "" CACHE INTERNAL "Thread-local storage keyword in compiler")
endif()
endif()
cmake_pop_check_state()
endif()
endmacro()
@@ -0,0 +1,750 @@
# Copyright (c) 2012 - 2017, Lars Bilke
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without modification,
# are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors
# may be used to endorse or promote products derived from this software without
# specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# CHANGES:
#
# 2012-01-31, Lars Bilke
# - Enable Code Coverage
#
# 2013-09-17, Joakim Söderberg
# - Added support for Clang.
# - Some additional usage instructions.
#
# 2016-02-03, Lars Bilke
# - Refactored functions to use named parameters
#
# 2017-06-02, Lars Bilke
# - Merged with modified version from github.com/ufz/ogs
#
# 2019-05-06, Anatolii Kurotych
# - Remove unnecessary --coverage flag
#
# 2019-12-13, FeRD (Frank Dana)
# - Deprecate COVERAGE_LCOVR_EXCLUDES and COVERAGE_GCOVR_EXCLUDES lists in favor
# of tool-agnostic COVERAGE_EXCLUDES variable, or EXCLUDE setup arguments.
# - CMake 3.4+: All excludes can be specified relative to BASE_DIRECTORY
# - All setup functions: accept BASE_DIRECTORY, EXCLUDE list
# - Set lcov basedir with -b argument
# - Add automatic --demangle-cpp in lcovr, if 'c++filt' is available (can be
# overridden with NO_DEMANGLE option in setup_target_for_coverage_lcovr().)
# - Delete output dir, .info file on 'make clean'
# - Remove Python detection, since version mismatches will break gcovr
# - Minor cleanup (lowercase function names, update examples...)
#
# 2019-12-19, FeRD (Frank Dana)
# - Rename Lcov outputs, make filtered file canonical, fix cleanup for targets
#
# 2020-01-19, Bob Apthorpe
# - Added gfortran support
#
# 2020-02-17, FeRD (Frank Dana)
# - Make all add_custom_target()s VERBATIM to auto-escape wildcard characters
# in EXCLUDEs, and remove manual escaping from gcovr targets
#
# 2021-01-19, Robin Mueller
# - Add CODE_COVERAGE_VERBOSE option which will allow to print out commands which are run
# - Added the option for users to set the GCOVR_ADDITIONAL_ARGS variable to supply additional
# flags to the gcovr command
#
# 2020-05-04, Mihchael Davis
# - Add -fprofile-abs-path to make gcno files contain absolute paths
# - Fix BASE_DIRECTORY not working when defined
# - Change BYPRODUCT from folder to index.html to stop ninja from complaining about double defines
#
# 2021-05-10, Martin Stump
# - Check if the generator is multi-config before warning about non-Debug builds
#
# 2022-02-22, Marko Wehle
# - Change gcovr output from -o <filename> for --xml <filename> and --html <filename> output respectively.
# This will allow for Multiple Output Formats at the same time by making use of GCOVR_ADDITIONAL_ARGS, e.g. GCOVR_ADDITIONAL_ARGS "--txt".
#
# 2022-09-28, Sebastian Mueller
# - fix append_coverage_compiler_flags_to_target to correctly add flags
# - replace "-fprofile-arcs -ftest-coverage" with "--coverage" (equivalent)
#
# USAGE:
#
# 1. Copy this file into your cmake modules path.
#
# 2. Add the following line to your CMakeLists.txt (best inside an if-condition
# using a CMake option() to enable it just optionally):
# include(CodeCoverage)
#
# 3. Append necessary compiler flags for all supported source files:
# append_coverage_compiler_flags()
# Or for specific target:
# append_coverage_compiler_flags_to_target(YOUR_TARGET_NAME)
#
# 3.a (OPTIONAL) Set appropriate optimization flags, e.g. -O0, -O1 or -Og
#
# 4. If you need to exclude additional directories from the report, specify them
# using full paths in the COVERAGE_EXCLUDES variable before calling
# setup_target_for_coverage_*().
# Example:
# set(COVERAGE_EXCLUDES
# '${PROJECT_SOURCE_DIR}/src/dir1/*'
# '/path/to/my/src/dir2/*')
# Or, use the EXCLUDE argument to setup_target_for_coverage_*().
# Example:
# setup_target_for_coverage_lcov(
# NAME coverage
# EXECUTABLE testrunner
# EXCLUDE "${PROJECT_SOURCE_DIR}/src/dir1/*" "/path/to/my/src/dir2/*")
#
# 4.a NOTE: With CMake 3.4+, COVERAGE_EXCLUDES or EXCLUDE can also be set
# relative to the BASE_DIRECTORY (default: PROJECT_SOURCE_DIR)
# Example:
# set(COVERAGE_EXCLUDES "dir1/*")
# setup_target_for_coverage_gcovr_html(
# NAME coverage
# EXECUTABLE testrunner
# BASE_DIRECTORY "${PROJECT_SOURCE_DIR}/src"
# EXCLUDE "dir2/*")
#
# 5. Use the functions described below to create a custom make target which
# runs your test executable and produces a code coverage report.
#
# 6. Build a Debug build:
# cmake -DCMAKE_BUILD_TYPE=Debug ..
# make
# make my_coverage_target
#
include(CMakeParseArguments)
option(CODE_COVERAGE_VERBOSE "Verbose information" FALSE)
# Check prereqs
find_program( GCOV_PATH gcov )
find_program( LCOV_PATH NAMES lcov lcov.bat lcov.exe lcov.perl)
find_program( FASTCOV_PATH NAMES fastcov fastcov.py )
find_program( GENHTML_PATH NAMES genhtml genhtml.perl genhtml.bat )
find_program( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/scripts/test)
find_program( CPPFILT_PATH NAMES c++filt )
if(NOT GCOV_PATH)
message(FATAL_ERROR "gcov not found! Aborting...")
endif() # NOT GCOV_PATH
# Check supported compiler (Clang, GNU and Flang)
get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
foreach(LANG ${LANGUAGES})
if("${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(Apple)?[Cc]lang")
if("${CMAKE_${LANG}_COMPILER_VERSION}" VERSION_LESS 3)
message(FATAL_ERROR "Clang version must be 3.0.0 or greater! Aborting...")
endif()
elseif(NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "GNU"
AND NOT "${CMAKE_${LANG}_COMPILER_ID}" MATCHES "(LLVM)?[Ff]lang")
message(FATAL_ERROR "Compiler is not GNU or Flang! Aborting...")
endif()
endforeach()
set(COVERAGE_COMPILER_FLAGS "-g --coverage"
CACHE INTERNAL "")
if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)")
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-fprofile-abs-path HAVE_cxx_fprofile_abs_path)
if(HAVE_cxx_fprofile_abs_path)
set(COVERAGE_CXX_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
endif()
endif()
if(CMAKE_C_COMPILER_ID MATCHES "(GNU|Clang)")
include(CheckCCompilerFlag)
check_c_compiler_flag(-fprofile-abs-path HAVE_c_fprofile_abs_path)
if(HAVE_c_fprofile_abs_path)
set(COVERAGE_C_COMPILER_FLAGS "${COVERAGE_COMPILER_FLAGS} -fprofile-abs-path")
endif()
endif()
set(CMAKE_Fortran_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the Fortran compiler during coverage builds."
FORCE )
set(CMAKE_CXX_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the C++ compiler during coverage builds."
FORCE )
set(CMAKE_C_FLAGS_COVERAGE
${COVERAGE_COMPILER_FLAGS}
CACHE STRING "Flags used by the C compiler during coverage builds."
FORCE )
set(CMAKE_EXE_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used for linking binaries during coverage builds."
FORCE )
set(CMAKE_SHARED_LINKER_FLAGS_COVERAGE
""
CACHE STRING "Flags used by the shared libraries linker during coverage builds."
FORCE )
mark_as_advanced(
CMAKE_Fortran_FLAGS_COVERAGE
CMAKE_CXX_FLAGS_COVERAGE
CMAKE_C_FLAGS_COVERAGE
CMAKE_EXE_LINKER_FLAGS_COVERAGE
CMAKE_SHARED_LINKER_FLAGS_COVERAGE )
get_property(GENERATOR_IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG))
message(WARNING "Code coverage results with an optimised (non-Debug) build may be misleading")
endif() # NOT (CMAKE_BUILD_TYPE STREQUAL "Debug" OR GENERATOR_IS_MULTI_CONFIG)
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
link_libraries(gcov)
endif()
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# setup_target_for_coverage_lcov(
# NAME testrunner_coverage # New target name
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES testrunner # Dependencies to build first
# BASE_DIRECTORY "../" # Base directory for report
# # (defaults to PROJECT_SOURCE_DIR)
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
# # to BASE_DIRECTORY, with CMake 3.4+)
# NO_DEMANGLE # Don't demangle C++ symbols
# # even if c++filt is found
# )
function(setup_target_for_coverage_lcov)
set(options NO_DEMANGLE SONARQUBE)
set(oneValueArgs BASE_DIRECTORY NAME)
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES LCOV_ARGS GENHTML_ARGS)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT LCOV_PATH)
message(FATAL_ERROR "lcov not found! Aborting...")
endif() # NOT LCOV_PATH
if(NOT GENHTML_PATH)
message(FATAL_ERROR "genhtml not found! Aborting...")
endif() # NOT GENHTML_PATH
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
if(DEFINED Coverage_BASE_DIRECTORY)
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
else()
set(BASEDIR ${PROJECT_SOURCE_DIR})
endif()
# Collect excludes (CMake 3.4+: Also compute absolute paths)
set(LCOV_EXCLUDES "")
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_LCOV_EXCLUDES})
if(CMAKE_VERSION VERSION_GREATER 3.4)
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
endif()
list(APPEND LCOV_EXCLUDES "${EXCLUDE}")
endforeach()
list(REMOVE_DUPLICATES LCOV_EXCLUDES)
# Conditional arguments
if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
set(GENHTML_EXTRA_ARGS "--demangle-cpp")
endif()
# Setting up commands which will be run to generate coverage data.
# Cleanup lcov
set(LCOV_CLEAN_CMD
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory .
-b ${BASEDIR} --zerocounters
)
# Create baseline to make sure untouched files show up in the report
set(LCOV_BASELINE_CMD
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -c -i -d . -b
${BASEDIR} -o ${Coverage_NAME}.base
)
# Run tests
set(LCOV_EXEC_TESTS_CMD
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
)
# Capturing lcov counters and generating report
set(LCOV_CAPTURE_CMD
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --directory . -b
${BASEDIR} --capture --output-file ${Coverage_NAME}.capture
)
# add baseline counters
set(LCOV_BASELINE_COUNT_CMD
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} -a ${Coverage_NAME}.base
-a ${Coverage_NAME}.capture --output-file ${Coverage_NAME}.total
)
# filter collected data to final coverage report
set(LCOV_FILTER_CMD
${LCOV_PATH} ${Coverage_LCOV_ARGS} --gcov-tool ${GCOV_PATH} --remove
${Coverage_NAME}.total ${LCOV_EXCLUDES} --output-file ${Coverage_NAME}.info
)
# Generate HTML output
set(LCOV_GEN_HTML_CMD
${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS} -o
${Coverage_NAME} ${Coverage_NAME}.info
)
if(${Coverage_SONARQUBE})
# Generate SonarQube output
set(GCOVR_XML_CMD
${GCOVR_PATH} --sonarqube ${Coverage_NAME}_sonarqube.xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
)
set(GCOVR_XML_CMD_COMMAND
COMMAND ${GCOVR_XML_CMD}
)
set(GCOVR_XML_CMD_BYPRODUCTS ${Coverage_NAME}_sonarqube.xml)
set(GCOVR_XML_CMD_COMMENT COMMENT "SonarQube code coverage info report saved in ${Coverage_NAME}_sonarqube.xml.")
endif()
if(CODE_COVERAGE_VERBOSE)
message(STATUS "Executed command report")
message(STATUS "Command to clean up lcov: ")
string(REPLACE ";" " " LCOV_CLEAN_CMD_SPACED "${LCOV_CLEAN_CMD}")
message(STATUS "${LCOV_CLEAN_CMD_SPACED}")
message(STATUS "Command to create baseline: ")
string(REPLACE ";" " " LCOV_BASELINE_CMD_SPACED "${LCOV_BASELINE_CMD}")
message(STATUS "${LCOV_BASELINE_CMD_SPACED}")
message(STATUS "Command to run the tests: ")
string(REPLACE ";" " " LCOV_EXEC_TESTS_CMD_SPACED "${LCOV_EXEC_TESTS_CMD}")
message(STATUS "${LCOV_EXEC_TESTS_CMD_SPACED}")
message(STATUS "Command to capture counters and generate report: ")
string(REPLACE ";" " " LCOV_CAPTURE_CMD_SPACED "${LCOV_CAPTURE_CMD}")
message(STATUS "${LCOV_CAPTURE_CMD_SPACED}")
message(STATUS "Command to add baseline counters: ")
string(REPLACE ";" " " LCOV_BASELINE_COUNT_CMD_SPACED "${LCOV_BASELINE_COUNT_CMD}")
message(STATUS "${LCOV_BASELINE_COUNT_CMD_SPACED}")
message(STATUS "Command to filter collected data: ")
string(REPLACE ";" " " LCOV_FILTER_CMD_SPACED "${LCOV_FILTER_CMD}")
message(STATUS "${LCOV_FILTER_CMD_SPACED}")
message(STATUS "Command to generate lcov HTML output: ")
string(REPLACE ";" " " LCOV_GEN_HTML_CMD_SPACED "${LCOV_GEN_HTML_CMD}")
message(STATUS "${LCOV_GEN_HTML_CMD_SPACED}")
if(${Coverage_SONARQUBE})
message(STATUS "Command to generate SonarQube XML output: ")
string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}")
message(STATUS "${GCOVR_XML_CMD_SPACED}")
endif()
endif()
# Setup target
add_custom_target(${Coverage_NAME}
COMMAND ${LCOV_CLEAN_CMD}
COMMAND ${LCOV_BASELINE_CMD}
COMMAND ${LCOV_EXEC_TESTS_CMD}
COMMAND ${LCOV_CAPTURE_CMD}
COMMAND ${LCOV_BASELINE_COUNT_CMD}
COMMAND ${LCOV_FILTER_CMD}
COMMAND ${LCOV_GEN_HTML_CMD}
${GCOVR_XML_CMD_COMMAND}
# Set output files as GENERATED (will be removed on 'make clean')
BYPRODUCTS
${Coverage_NAME}.base
${Coverage_NAME}.capture
${Coverage_NAME}.total
${Coverage_NAME}.info
${GCOVR_XML_CMD_BYPRODUCTS}
${Coverage_NAME}/index.html
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
VERBATIM # Protect arguments to commands
COMMENT "Resetting code coverage counters to zero. Processing code coverage counters and generating report."
)
# Show where to find the lcov info report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND true
COMMENT "Lcov code coverage info report saved in ${Coverage_NAME}.info."
${GCOVR_XML_CMD_COMMENT}
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND true
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
)
endfunction() # setup_target_for_coverage_lcov
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# setup_target_for_coverage_gcovr_xml(
# NAME ctest_coverage # New target name
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES executable_target # Dependencies to build first
# BASE_DIRECTORY "../" # Base directory for report
# # (defaults to PROJECT_SOURCE_DIR)
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
# # to BASE_DIRECTORY, with CMake 3.4+)
# )
# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the
# GCVOR command.
function(setup_target_for_coverage_gcovr_xml)
set(options NONE)
set(oneValueArgs BASE_DIRECTORY NAME)
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT GCOVR_PATH)
message(FATAL_ERROR "gcovr not found! Aborting...")
endif() # NOT GCOVR_PATH
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
if(DEFINED Coverage_BASE_DIRECTORY)
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
else()
set(BASEDIR ${PROJECT_SOURCE_DIR})
endif()
# Collect excludes (CMake 3.4+: Also compute absolute paths)
set(GCOVR_EXCLUDES "")
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
if(CMAKE_VERSION VERSION_GREATER 3.4)
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
endif()
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
endforeach()
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
# Combine excludes to several -e arguments
set(GCOVR_EXCLUDE_ARGS "")
foreach(EXCLUDE ${GCOVR_EXCLUDES})
list(APPEND GCOVR_EXCLUDE_ARGS "-e")
list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
endforeach()
# Set up commands which will be run to generate coverage data
# Run tests
set(GCOVR_XML_EXEC_TESTS_CMD
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
)
# Running gcovr
set(GCOVR_XML_CMD
${GCOVR_PATH} --xml ${Coverage_NAME}.xml -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
)
if(CODE_COVERAGE_VERBOSE)
message(STATUS "Executed command report")
message(STATUS "Command to run tests: ")
string(REPLACE ";" " " GCOVR_XML_EXEC_TESTS_CMD_SPACED "${GCOVR_XML_EXEC_TESTS_CMD}")
message(STATUS "${GCOVR_XML_EXEC_TESTS_CMD_SPACED}")
message(STATUS "Command to generate gcovr XML coverage data: ")
string(REPLACE ";" " " GCOVR_XML_CMD_SPACED "${GCOVR_XML_CMD}")
message(STATUS "${GCOVR_XML_CMD_SPACED}")
endif()
add_custom_target(${Coverage_NAME}
COMMAND ${GCOVR_XML_EXEC_TESTS_CMD}
COMMAND ${GCOVR_XML_CMD}
BYPRODUCTS ${Coverage_NAME}.xml
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
VERBATIM # Protect arguments to commands
COMMENT "Running gcovr to produce Cobertura code coverage report."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND true
COMMENT "Cobertura code coverage report saved in ${Coverage_NAME}.xml."
)
endfunction() # setup_target_for_coverage_gcovr_xml
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# setup_target_for_coverage_gcovr_html(
# NAME ctest_coverage # New target name
# EXECUTABLE ctest -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES executable_target # Dependencies to build first
# BASE_DIRECTORY "../" # Base directory for report
# # (defaults to PROJECT_SOURCE_DIR)
# EXCLUDE "src/dir1/*" "src/dir2/*" # Patterns to exclude (can be relative
# # to BASE_DIRECTORY, with CMake 3.4+)
# )
# The user can set the variable GCOVR_ADDITIONAL_ARGS to supply additional flags to the
# GCVOR command.
function(setup_target_for_coverage_gcovr_html)
set(options NONE)
set(oneValueArgs BASE_DIRECTORY NAME)
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT GCOVR_PATH)
message(FATAL_ERROR "gcovr not found! Aborting...")
endif() # NOT GCOVR_PATH
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
if(DEFINED Coverage_BASE_DIRECTORY)
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
else()
set(BASEDIR ${PROJECT_SOURCE_DIR})
endif()
# Collect excludes (CMake 3.4+: Also compute absolute paths)
set(GCOVR_EXCLUDES "")
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_GCOVR_EXCLUDES})
if(CMAKE_VERSION VERSION_GREATER 3.4)
get_filename_component(EXCLUDE ${EXCLUDE} ABSOLUTE BASE_DIR ${BASEDIR})
endif()
list(APPEND GCOVR_EXCLUDES "${EXCLUDE}")
endforeach()
list(REMOVE_DUPLICATES GCOVR_EXCLUDES)
# Combine excludes to several -e arguments
set(GCOVR_EXCLUDE_ARGS "")
foreach(EXCLUDE ${GCOVR_EXCLUDES})
list(APPEND GCOVR_EXCLUDE_ARGS "-e")
list(APPEND GCOVR_EXCLUDE_ARGS "${EXCLUDE}")
endforeach()
# Set up commands which will be run to generate coverage data
# Run tests
set(GCOVR_HTML_EXEC_TESTS_CMD
${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS}
)
# Create folder
set(GCOVR_HTML_FOLDER_CMD
${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/${Coverage_NAME}
)
# Running gcovr
set(GCOVR_HTML_CMD
${GCOVR_PATH} --html ${Coverage_NAME}/index.html --html-details -r ${BASEDIR} ${GCOVR_ADDITIONAL_ARGS}
${GCOVR_EXCLUDE_ARGS} --object-directory=${PROJECT_BINARY_DIR}
)
if(CODE_COVERAGE_VERBOSE)
message(STATUS "Executed command report")
message(STATUS "Command to run tests: ")
string(REPLACE ";" " " GCOVR_HTML_EXEC_TESTS_CMD_SPACED "${GCOVR_HTML_EXEC_TESTS_CMD}")
message(STATUS "${GCOVR_HTML_EXEC_TESTS_CMD_SPACED}")
message(STATUS "Command to create a folder: ")
string(REPLACE ";" " " GCOVR_HTML_FOLDER_CMD_SPACED "${GCOVR_HTML_FOLDER_CMD}")
message(STATUS "${GCOVR_HTML_FOLDER_CMD_SPACED}")
message(STATUS "Command to generate gcovr HTML coverage data: ")
string(REPLACE ";" " " GCOVR_HTML_CMD_SPACED "${GCOVR_HTML_CMD}")
message(STATUS "${GCOVR_HTML_CMD_SPACED}")
endif()
add_custom_target(${Coverage_NAME}
COMMAND ${GCOVR_HTML_EXEC_TESTS_CMD}
COMMAND ${GCOVR_HTML_FOLDER_CMD}
COMMAND ${GCOVR_HTML_CMD}
BYPRODUCTS ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html # report directory
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
VERBATIM # Protect arguments to commands
COMMENT "Running gcovr to produce HTML code coverage report."
)
# Show info where to find the report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND true
COMMENT "Open ./${Coverage_NAME}/index.html in your browser to view the coverage report."
)
endfunction() # setup_target_for_coverage_gcovr_html
# Defines a target for running and collection code coverage information
# Builds dependencies, runs the given executable and outputs reports.
# NOTE! The executable should always have a ZERO as exit code otherwise
# the coverage generation will not complete.
#
# setup_target_for_coverage_fastcov(
# NAME testrunner_coverage # New target name
# EXECUTABLE testrunner -j ${PROCESSOR_COUNT} # Executable in PROJECT_BINARY_DIR
# DEPENDENCIES testrunner # Dependencies to build first
# BASE_DIRECTORY "../" # Base directory for report
# # (defaults to PROJECT_SOURCE_DIR)
# EXCLUDE "src/dir1/" "src/dir2/" # Patterns to exclude.
# NO_DEMANGLE # Don't demangle C++ symbols
# # even if c++filt is found
# SKIP_HTML # Don't create html report
# POST_CMD perl -i -pe s!${PROJECT_SOURCE_DIR}/!!g ctest_coverage.json # E.g. for stripping source dir from file paths
# )
function(setup_target_for_coverage_fastcov)
set(options NO_DEMANGLE SKIP_HTML)
set(oneValueArgs BASE_DIRECTORY NAME)
set(multiValueArgs EXCLUDE EXECUTABLE EXECUTABLE_ARGS DEPENDENCIES FASTCOV_ARGS GENHTML_ARGS POST_CMD)
cmake_parse_arguments(Coverage "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if(NOT FASTCOV_PATH)
message(FATAL_ERROR "fastcov not found! Aborting...")
endif()
if(NOT Coverage_SKIP_HTML AND NOT GENHTML_PATH)
message(FATAL_ERROR "genhtml not found! Aborting...")
endif()
# Set base directory (as absolute path), or default to PROJECT_SOURCE_DIR
if(Coverage_BASE_DIRECTORY)
get_filename_component(BASEDIR ${Coverage_BASE_DIRECTORY} ABSOLUTE)
else()
set(BASEDIR ${PROJECT_SOURCE_DIR})
endif()
# Collect excludes (Patterns, not paths, for fastcov)
set(FASTCOV_EXCLUDES "")
foreach(EXCLUDE ${Coverage_EXCLUDE} ${COVERAGE_EXCLUDES} ${COVERAGE_FASTCOV_EXCLUDES})
list(APPEND FASTCOV_EXCLUDES "${EXCLUDE}")
endforeach()
list(REMOVE_DUPLICATES FASTCOV_EXCLUDES)
# Conditional arguments
if(CPPFILT_PATH AND NOT ${Coverage_NO_DEMANGLE})
set(GENHTML_EXTRA_ARGS "--demangle-cpp")
endif()
# Set up commands which will be run to generate coverage data
set(FASTCOV_EXEC_TESTS_CMD ${Coverage_EXECUTABLE} ${Coverage_EXECUTABLE_ARGS})
set(FASTCOV_CAPTURE_CMD ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH}
--search-directory ${BASEDIR}
--process-gcno
--output ${Coverage_NAME}.json
--exclude ${FASTCOV_EXCLUDES}
)
set(FASTCOV_CONVERT_CMD ${FASTCOV_PATH}
-C ${Coverage_NAME}.json --lcov --output ${Coverage_NAME}.info
)
if(Coverage_SKIP_HTML)
set(FASTCOV_HTML_CMD ";")
else()
set(FASTCOV_HTML_CMD ${GENHTML_PATH} ${GENHTML_EXTRA_ARGS} ${Coverage_GENHTML_ARGS}
-o ${Coverage_NAME} ${Coverage_NAME}.info
)
endif()
set(FASTCOV_POST_CMD ";")
if(Coverage_POST_CMD)
set(FASTCOV_POST_CMD ${Coverage_POST_CMD})
endif()
if(CODE_COVERAGE_VERBOSE)
message(STATUS "Code coverage commands for target ${Coverage_NAME} (fastcov):")
message(" Running tests:")
string(REPLACE ";" " " FASTCOV_EXEC_TESTS_CMD_SPACED "${FASTCOV_EXEC_TESTS_CMD}")
message(" ${FASTCOV_EXEC_TESTS_CMD_SPACED}")
message(" Capturing fastcov counters and generating report:")
string(REPLACE ";" " " FASTCOV_CAPTURE_CMD_SPACED "${FASTCOV_CAPTURE_CMD}")
message(" ${FASTCOV_CAPTURE_CMD_SPACED}")
message(" Converting fastcov .json to lcov .info:")
string(REPLACE ";" " " FASTCOV_CONVERT_CMD_SPACED "${FASTCOV_CONVERT_CMD}")
message(" ${FASTCOV_CONVERT_CMD_SPACED}")
if(NOT Coverage_SKIP_HTML)
message(" Generating HTML report: ")
string(REPLACE ";" " " FASTCOV_HTML_CMD_SPACED "${FASTCOV_HTML_CMD}")
message(" ${FASTCOV_HTML_CMD_SPACED}")
endif()
if(Coverage_POST_CMD)
message(" Running post command: ")
string(REPLACE ";" " " FASTCOV_POST_CMD_SPACED "${FASTCOV_POST_CMD}")
message(" ${FASTCOV_POST_CMD_SPACED}")
endif()
endif()
# Setup target
add_custom_target(${Coverage_NAME}
# Cleanup fastcov
COMMAND ${FASTCOV_PATH} ${Coverage_FASTCOV_ARGS} --gcov ${GCOV_PATH}
--search-directory ${BASEDIR}
--zerocounters
COMMAND ${FASTCOV_EXEC_TESTS_CMD}
COMMAND ${FASTCOV_CAPTURE_CMD}
COMMAND ${FASTCOV_CONVERT_CMD}
COMMAND ${FASTCOV_HTML_CMD}
COMMAND ${FASTCOV_POST_CMD}
# Set output files as GENERATED (will be removed on 'make clean')
BYPRODUCTS
${Coverage_NAME}.info
${Coverage_NAME}.json
${Coverage_NAME}/index.html # report directory
WORKING_DIRECTORY ${PROJECT_BINARY_DIR}
DEPENDS ${Coverage_DEPENDENCIES}
VERBATIM # Protect arguments to commands
COMMENT "Resetting code coverage counters to zero. Processing code coverage counters and generating report."
)
set(INFO_MSG "fastcov code coverage info report saved in ${Coverage_NAME}.info and ${Coverage_NAME}.json.")
if(NOT Coverage_SKIP_HTML)
string(APPEND INFO_MSG " Open ${PROJECT_BINARY_DIR}/${Coverage_NAME}/index.html in your browser to view the coverage report.")
endif()
# Show where to find the fastcov info report
add_custom_command(TARGET ${Coverage_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E echo ${INFO_MSG}
)
endfunction() # setup_target_for_coverage_fastcov
function(append_coverage_compiler_flags)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
set(CMAKE_Fortran_FLAGS "${CMAKE_Fortran_FLAGS} ${COVERAGE_COMPILER_FLAGS}" PARENT_SCOPE)
message(STATUS "Appending code coverage compiler flags: ${COVERAGE_COMPILER_FLAGS}")
endfunction() # append_coverage_compiler_flags
# Setup coverage for specific library
function(append_coverage_compiler_flags_to_target name)
separate_arguments(_flag_list NATIVE_COMMAND "${COVERAGE_COMPILER_FLAGS}")
target_compile_options(${name} PRIVATE ${_flag_list})
if(CMAKE_C_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_Fortran_COMPILER_ID STREQUAL "GNU")
target_link_libraries(${name} PRIVATE gcov)
endif()
endfunction()
@@ -0,0 +1,85 @@
# https://raw.githubusercontent.com/dune-project/dune-istl/master/cmake/modules/FindARPACK.cmake
#
# This file is taken from:
#
# DUNE, the Distributed and Unified Numerics Environment
# GPLv2 licensed
#
# .. cmake_module::
#
# Module that checks whether ARPACK is available and usable.
#
# Variables used by this module which you may want to set:
#
# :ref:`ARPACK_ROOT`
# Path list to search for ARPACK.
#
# Sets the following variables:
#
# :code:`ARPACK_FOUND`
# True if ARPACK available.
#
# :code:`ARPACK_LIBRARIES`
# Link against these libraries to use ARPACK.
#
# .. cmake_variable:: ARPACK_ROOT
#
# You may set this variable to have :ref:`FindARPACK` look
# for the ARPACK package in the given path before inspecting
# system paths.
#
# look for library, only at positions given by the user
find_library(ARPACK_LIBRARY
NAMES "arpack"
PATHS ${ARPACK_PREFIX} ${ARPACK_ROOT}
PATH_SUFFIXES "lib" "lib32" "lib64"
NO_DEFAULT_PATH
)
# look for library files, including default paths
find_library(ARPACK_LIBRARY
NAMES "arpack"
PATH_SUFFIXES "lib" "lib32" "lib64"
)
# check header usability
include(CMakePushCheckState)
cmake_push_check_state()
# we need if clauses here because variable is set variable-NOTFOUND if the
# searches above were not successful; without them CMake print errors like:
# "CMake Error: The following variables are used in this project, but they
# are set to NOTFOUND. Please set them or make sure they are set and tested
# correctly in the CMake files."
if(ARPACK_LIBRARY)
set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${ARPACK_LIBRARY})
endif()
# end of header usability check
cmake_pop_check_state()
# behave like a CMake module is supposed to behave
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
"ARPACK"
DEFAULT_MSG
ARPACK_LIBRARY
)
# hide the introduced cmake cached variables in cmake GUIs
mark_as_advanced(ARPACK_LIBRARY)
# if headers are found, store results
if(ARPACK_FOUND)
set(ARPACK_LIBRARIES ${ARPACK_LIBRARY})
# log result
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Determing location of ARPACK succeeded:\n"
"Libraries to link against: ${ARPACK_LIBRARIES}\n\n")
else()
# log errornous result
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Determing location of ARPACK failed:\n"
"Libraries to link against: ${ARPACK_LIBRARIES}\n\n")
endif()
@@ -0,0 +1,81 @@
#[=======================================================================[.rst:
FindGLPK
--------
Finds the GLPK library.
Result Variables
^^^^^^^^^^^^^^^^
This will define the following variables:
``GLPK_FOUND``
True if the system has the GLPK library.
``GLPK_VERSION``
The version of the GLPK library which was found.
``GLPK_INCLUDE_DIRS``
Include directories needed to use Foo.
``GLPK_LIBRARIES``
Libraries needed to link to Foo.
Cache Variables
^^^^^^^^^^^^^^^
The following cache variables may also be set:
``GLPK_INCLUDE_DIR``
The directory containing ``glpk.h``.
``GLPK_LIBRARY``
The path to the GLPK library.
#]=======================================================================]
find_path(GLPK_INCLUDE_DIR
NAMES glpk.h
)
find_library(GLPK_LIBRARY
NAMES glpk
)
# parse version from header
if(GLPK_INCLUDE_DIR)
set(GLPK_VERSION_FILE ${GLPK_INCLUDE_DIR}/glpk.h)
file(READ ${GLPK_VERSION_FILE} GLPK_VERSION_FILE_CONTENTS)
string(REGEX MATCH "#define[ ]+GLP_MAJOR_VERSION[ ]+[0-9]+"
GLPK_VERSION_MAJOR "${GLPK_VERSION_FILE_CONTENTS}")
string(REGEX REPLACE "#define[ ]+GLP_MAJOR_VERSION[ ]+([0-9]+)" "\\1"
GLPK_VERSION_MAJOR "${GLPK_VERSION_MAJOR}")
string(REGEX MATCH "#define[ ]+GLP_MINOR_VERSION[ ]+[0-9]+"
GLPK_VERSION_MINOR "${GLPK_VERSION_FILE_CONTENTS}")
string(REGEX REPLACE "#define[ ]+GLP_MINOR_VERSION[ ]+([0-9]+)" "\\1"
GLPK_VERSION_MINOR "${GLPK_VERSION_MINOR}")
set(GLPK_VERSION "${GLPK_VERSION_MAJOR}.${GLPK_VERSION_MINOR}")
# compatibility variables
set(GLPK_VERSION_STRING "${GLPK_VERSION}")
endif()
# behave like a CMake module is supposed to behave
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(GLPK
FOUND_VAR GLPK_FOUND
REQUIRED_VARS
GLPK_LIBRARY
GLPK_INCLUDE_DIR
VERSION_VAR GLPK_VERSION
)
# hide the introduced cmake cached variables in cmake GUIs
mark_as_advanced(
GLPK_INCLUDE_DIR
GLPK_LIBRARY
)
if(GLPK_FOUND)
set(GLPK_LIBRARIES ${GLPK_LIBRARY})
set(GLPK_INCLUDE_DIRS ${GLPK_INCLUDE_DIR})
endif()
@@ -0,0 +1,36 @@
# Inspired by http://code.google.com/p/origin/source/browse/trunk/cmake/FindGMP.cmake
# Copyright (c) 2008-2010 Kent State University
# Copyright (c) 2011-2012 Texas A&M University
#
# This file is distributed under the MIT License. See
# http://www.opensource.org/licenses/mit-license.php for terms and conditions.
#
# Some modifications made by Tamas Nepusz to ensure that the module fits better
# with the de facto conventions of FindXXX.cmake scripts
find_path(GMP_INCLUDE_DIR
NAMES gmp.h
)
find_library(GMP_LIBRARY
NAMES gmp
)
# behave like a CMake module is supposed to behave
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
"GMP"
DEFAULT_MSG
GMP_LIBRARY
GMP_INCLUDE_DIR
)
# hide the introduced cmake cached variables in cmake GUIs
mark_as_advanced(GMP_INCLUDE_DIR)
mark_as_advanced(GMP_LIBRARY)
if(GMP_FOUND)
set(GMP_LIBRARIES ${GMP_LIBRARY})
set(GMP_INCLUDE_DIRS ${GMP_INCLUDE_DIR})
endif()
@@ -0,0 +1,63 @@
# Inspired by http://code.google.com/p/origin/source/browse/trunk/cmake/FindGMP.cmake
# Copyright (c) 2021 Tamas Nepusz
#
# This file is distributed under the MIT License. See
# http://www.opensource.org/licenses/mit-license.php for terms and conditions.
#
# Some modifications made by Tamas Nepusz to ensure that the module fits better
# with the de facto conventions of FindXXX.cmake scripts
find_path(PLFIT_INCLUDE_DIR
NAMES plfit.h
PATH_SUFFIXES plfit
)
find_library(PLFIT_LIBRARY
NAMES plfit
)
# parse version from header
if(PLFIT_INCLUDE_DIR)
set(PLFIT_VERSION_FILE ${PLFIT_INCLUDE_DIR}/plfit_version.h)
file(READ ${PLFIT_VERSION_FILE} PLFIT_VERSION_FILE_CONTENTS)
string(REGEX MATCH "#define[ ]+PLFIT_VERSION_MAJOR[ ]+[0-9]+"
PLFIT_VERSION_MAJOR "${PLFIT_VERSION_FILE_CONTENTS}")
string(REGEX REPLACE "#define[ ]+PLFIT_VERSION_MAJOR[ ]+([0-9]+)" "\\1"
PLFIT_VERSION_MAJOR "${PLFIT_VERSION_MAJOR}")
string(REGEX MATCH "#define[ ]+PLFIT_VERSION_MINOR[ ]+[0-9]+"
PLFIT_VERSION_MINOR "${PLFIT_VERSION_FILE_CONTENTS}")
string(REGEX REPLACE "#define[ ]+PLFIT_VERSION_MINOR[ ]+([0-9]+)" "\\1"
PLFIT_VERSION_MINOR "${PLFIT_VERSION_MINOR}")
string(REGEX MATCH "#define[ ]+PLFIT_VERSION_PATCH[ ]+[0-9]+"
PLFIT_VERSION_PATCH "${PLFIT_VERSION_FILE_CONTENTS}")
string(REGEX REPLACE "#define[ ]+PLFIT_VERSION_PATCH[ ]+([0-9]+)" "\\1"
PLFIT_VERSION_PATCH "${PLFIT_VERSION_PATCH}")
set(PLFIT_VERSION "${PLFIT_VERSION_MAJOR}.${PLFIT_VERSION_MINOR}.${PLFIT_VERSION_PATCH}")
# compatibility variables
set(PLFIT_VERSION_STRING "${PLFIT_VERSION}")
endif()
# behave like a CMake module is supposed to behave
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PLFIT
FOUND_VAR PLFIT_FOUND
REQUIRED_VARS
PLFIT_LIBRARY
PLFIT_INCLUDE_DIR
VERSION_VAR PLFIT_VERSION
)
# hide the introduced cmake cached variables in cmake GUIs
mark_as_advanced(PLFIT_INCLUDE_DIR)
mark_as_advanced(PLFIT_LIBRARY)
if(PLFIT_FOUND)
set(PLFIT_LIBRARIES ${PLFIT_LIBRARY})
set(PLFIT_INCLUDE_DIRS ${PLFIT_INCLUDE_DIR})
endif()
@@ -0,0 +1,166 @@
# - Returns a version string from Git
#
# These functions force a re-configure on each git commit so that you can
# trust the values of the variables in your build system.
#
# get_git_head_revision(<refspecvar> <hashvar> [<additional arguments to git describe> ...])
#
# Returns the refspec and sha hash of the current head revision
#
# git_describe(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe on the source tree, and adjusting
# the output so that it tests false if an error occurs.
#
# git_get_exact_tag(<var> [<additional arguments to git describe> ...])
#
# Returns the results of git describe --exact-match on the source tree,
# and adjusting the output so that it tests false if there was no exact
# matching tag.
#
# git_local_changes(<var>)
#
# Returns either "CLEAN" or "DIRTY" with respect to uncommitted changes.
# Uses the return code of "git diff-index --quiet HEAD --".
# Does not regard untracked files.
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
if(__get_git_revision_description)
return()
endif()
set(__get_git_revision_description YES)
# We must run the following at "include" time, not at function call time,
# to find the path to this module rather than the path to a calling list file
get_filename_component(_gitdescmoddir ${CMAKE_CURRENT_LIST_FILE} PATH)
function(get_git_head_revision _refspecvar _hashvar)
set(GIT_PARENT_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
while(NOT EXISTS "${GIT_DIR}") # .git dir not found, search parent directories
set(GIT_PREVIOUS_PARENT "${GIT_PARENT_DIR}")
get_filename_component(GIT_PARENT_DIR ${GIT_PARENT_DIR} PATH)
if(GIT_PARENT_DIR STREQUAL GIT_PREVIOUS_PARENT)
# We have reached the root directory, we are not in git
set(${_refspecvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
set(${_hashvar} "GITDIR-NOTFOUND" PARENT_SCOPE)
return()
endif()
set(GIT_DIR "${GIT_PARENT_DIR}/.git")
endwhile()
# check if this is a submodule
if(NOT IS_DIRECTORY ${GIT_DIR})
file(READ ${GIT_DIR} submodule)
string(REGEX REPLACE "gitdir: (.*)\n$" "\\1" GIT_DIR_RELATIVE ${submodule})
get_filename_component(SUBMODULE_DIR ${GIT_DIR} PATH)
get_filename_component(GIT_DIR ${SUBMODULE_DIR}/${GIT_DIR_RELATIVE} ABSOLUTE)
endif()
set(GIT_DATA "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/git-data")
if(NOT EXISTS "${GIT_DATA}")
file(MAKE_DIRECTORY "${GIT_DATA}")
endif()
if(NOT EXISTS "${GIT_DIR}/HEAD")
return()
endif()
set(HEAD_FILE "${GIT_DATA}/HEAD")
configure_file("${GIT_DIR}/HEAD" "${HEAD_FILE}" COPYONLY)
configure_file("${_gitdescmoddir}/GetGitRevisionDescription.cmake.in"
"${GIT_DATA}/grabRef.cmake"
@ONLY)
include("${GIT_DATA}/grabRef.cmake")
set(${_refspecvar} "${HEAD_REF}" PARENT_SCOPE)
set(${_hashvar} "${HEAD_HASH}" PARENT_SCOPE)
endfunction()
function(git_describe _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
return()
endif()
# TODO sanitize
#if((${ARGN}" MATCHES "&&") OR
# (ARGN MATCHES "||") OR
# (ARGN MATCHES "\\;"))
# message("Please report the following error to the project!")
# message(FATAL_ERROR "Looks like someone's doing something nefarious with git_describe! Passed arguments ${ARGN}")
#endif()
execute_process(COMMAND
"${GIT_EXECUTABLE}"
describe
${hash}
${ARGN}
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(NOT res EQUAL 0)
set(out "${out}-${res}-NOTFOUND")
endif()
set(${_var} "${out}" PARENT_SCOPE)
endfunction()
function(git_get_exact_tag _var)
git_describe(out --exact-match ${ARGN})
set(${_var} "${out}" PARENT_SCOPE)
endfunction()
function(git_local_changes _var)
if(NOT GIT_FOUND)
find_package(Git QUIET)
endif()
get_git_head_revision(refspec hash)
if(NOT GIT_FOUND)
set(${_var} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
if(NOT hash)
set(${_var} "HEAD-HASH-NOTFOUND" PARENT_SCOPE)
return()
endif()
execute_process(COMMAND
"${GIT_EXECUTABLE}"
diff-index --quiet HEAD --
WORKING_DIRECTORY
"${CMAKE_CURRENT_SOURCE_DIR}"
RESULT_VARIABLE
res
OUTPUT_VARIABLE
out
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE)
if(res EQUAL 0)
set(${_var} "CLEAN" PARENT_SCOPE)
else()
set(${_var} "DIRTY" PARENT_SCOPE)
endif()
endfunction()
@@ -0,0 +1,41 @@
#
# Internal file for GetGitRevisionDescription.cmake
#
# Requires CMake 2.6 or newer (uses the 'function' command)
#
# Original Author:
# 2009-2010 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
# http://academic.cleardefinition.com
# Iowa State University HCI Graduate Program/VRAC
#
# Copyright Iowa State University 2009-2010.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt)
set(HEAD_HASH)
file(READ "@HEAD_FILE@" HEAD_CONTENTS LIMIT 1024)
string(STRIP "${HEAD_CONTENTS}" HEAD_CONTENTS)
if(HEAD_CONTENTS MATCHES "ref")
# named branch
string(REPLACE "ref: " "" HEAD_REF "${HEAD_CONTENTS}")
if(EXISTS "@GIT_DIR@/${HEAD_REF}")
configure_file("@GIT_DIR@/${HEAD_REF}" "@GIT_DATA@/head-ref" COPYONLY)
else()
configure_file("@GIT_DIR@/packed-refs" "@GIT_DATA@/packed-refs" COPYONLY)
file(READ "@GIT_DATA@/packed-refs" PACKED_REFS)
if(${PACKED_REFS} MATCHES "([0-9a-z]*) ${HEAD_REF}")
set(HEAD_HASH "${CMAKE_MATCH_1}")
endif()
endif()
else()
# detached HEAD
configure_file("@GIT_DIR@/HEAD" "@GIT_DATA@/head-ref" COPYONLY)
endif()
if(NOT HEAD_HASH)
file(READ "@GIT_DATA@/head-ref" HEAD_HASH LIMIT 1024)
string(STRIP "${HEAD_HASH}" HEAD_HASH)
endif()
@@ -0,0 +1,26 @@
# This module provides function for joining paths
# known from from most languages
#
# Original license:
# SPDX-License-Identifier: (MIT OR CC0-1.0)
# Explicit permission given to distribute this module under
# the terms of the project as described in /LICENSE.rst.
# Copyright 2020 Jan Tojnar
# https://github.com/jtojnar/cmake-snips
#
# Modelled after Pythons os.path.join
# https://docs.python.org/3.7/library/os.path.html#os.path.join
# Windows not supported
function(join_paths joined_path first_path_segment)
set(temp_path "${first_path_segment}")
foreach(current_segment IN LISTS ARGN)
if(NOT ("${current_segment}" STREQUAL ""))
if(IS_ABSOLUTE "${current_segment}")
set(temp_path "${current_segment}")
else()
set(temp_path "${temp_path}/${current_segment}")
endif()
endif()
endforeach()
set(${joined_path} "${temp_path}" PARENT_SCOPE)
endfunction()
@@ -0,0 +1,39 @@
# ------------------------------------------------------------------------------
# Macro PAD_STRING
#
# This function pads a string on the left side with a specified character to
# reach the specified length. If the string length is already long enough or
# longer, the string will not be modified.
#
# PAD_STRING(OUT_VARIABLE DESIRED_LENGTH FILL_CHAR VALUE)
#
# OUT_VARIABLE: name of the resulting variable to create
# DESIRED_LENGTH: desired length of the generated string
# FILL_CHAR: character to use for padding
# VALUE: string to pad
#
# Copyright (C) 2011 by Johannes Wienke <jwienke at techfak dot uni-bielefeld dot de>
#
# This program is free software; you can redistribute it
# and/or modify it under the terms of the GNU General
# Public License as published by the Free Software Foundation;
# either version 2, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# ------------------------------------------------------------------------------
FUNCTION(PAD_STRING OUT_VARIABLE DESIRED_LENGTH FILL_CHAR VALUE)
STRING(LENGTH "${VALUE}" VALUE_LENGTH)
MATH(EXPR REQUIRED_PADS "${DESIRED_LENGTH} - ${VALUE_LENGTH}")
SET(PAD ${VALUE})
IF(REQUIRED_PADS GREATER 0)
MATH(EXPR REQUIRED_MINUS_ONE "${REQUIRED_PADS} - 1")
FOREACH(FOO RANGE ${REQUIRED_MINUS_ONE})
SET(PAD "${FILL_CHAR}${PAD}")
ENDFOREACH()
ENDIF()
SET(${OUT_VARIABLE} "${PAD}" PARENT_SCOPE)
ENDFUNCTION()
@@ -0,0 +1,34 @@
# Original source of this script:
# https://raw.githubusercontent.com/InsightSoftwareConsortium/ITK/master/CMake/PreventInSourceBuilds.cmake
#
# Thanks to the ITK project!
#
# This function will prevent in-source builds
function(AssureOutOfSourceBuilds)
# make sure the user doesn't play dirty with symlinks
get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH)
# disallow in-source builds
if("${srcdir}" STREQUAL "${bindir}")
message("##########################################################################")
message("# igraph should not be configured & built in the igraph source directory")
message("# You must run cmake in a build directory.")
message("#")
message("# Example:")
message("# mkdir build; cd build; cmake ..; make")
message("#")
message("# NOTE: Given that you already tried to make an in-source build")
message("# CMake have already created several files & directories")
message("# in your source tree. If you are using git, run 'git clean -dfx'")
message("# to start from scratch. If you don't have git, remove")
message("# CMakeCache.txt and the CMakeFiles/ folder from the top of")
message("# the source tree.")
message("#")
message("##########################################################################")
message("")
message(FATAL_ERROR "Quitting configuration")
endif()
endfunction()
AssureOutOfSourceBuilds()
@@ -0,0 +1,7 @@
option(USE_CCACHE "Use ccache to speed up compilation if it is installed" ON)
if(USE_CCACHE)
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}")
endif()
endif()
@@ -0,0 +1,27 @@
# Detect if certain attributes are supported by the compiler
# The result will be used to set macros in include/igraph_config.h
# GCC-style enum value deprecation
include(CheckCSourceCompiles)
include(CMakePushCheckState)
# Only check with Clang and GCC as we assume that the -Werror option is supported
# For other compilers, assume that the attribute is unsupported.
if(CMAKE_C_COMPILER_ID MATCHES "Clang|GNU")
cmake_push_check_state()
# Require compiling with no warning:
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -Werror")
check_c_source_compiles(
"enum { A __attribute__ ((deprecated)) = 0 }; int main(void) { return 0; }"
COMPILER_HAS_DEPRECATED_ENUMVAL_ATTR
)
cmake_pop_check_state()
else()
set(COMPILER_HAS_DEPRECATED_ENUMVAL_ATTR FALSE)
endif()
if(COMPILER_HAS_DEPRECATED_ENUMVAL_ATTR)
set(IGRAPH_DEPRECATED_ENUMVAL "__attribute__ ((deprecated))")
endif()
@@ -0,0 +1,43 @@
include(CMakeParseArguments)
function(add_benchmark NAME NAMESPACE)
set(TARGET_NAME ${NAMESPACE}_${NAME})
add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL ${PROJECT_SOURCE_DIR}/tests/benchmarks/${NAME}.c)
use_all_warnings(${TARGET_NAME})
add_dependencies(build_benchmarks ${TARGET_NAME})
target_link_libraries(${TARGET_NAME} PRIVATE igraph)
# Some benchmarks include plfit_sampling.h from plfit. The following ensures
# that the correct version is included, depending on whether plfit is vendored
target_include_directories(
${TARGET_NAME} PRIVATE
$<$<BOOL:${PLFIT_IS_VENDORED}>:$<TARGET_PROPERTY:plfit_vendored,INCLUDE_DIRECTORIES>>
$<$<BOOL:${PLFIT_INCLUDE_DIR}>:${PLFIT_INCLUDE_DIR}>
)
if (MSVC)
# Add MSVC-specific include path for some headers that are missing on Windows
target_include_directories(${TARGET_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/msvc/include)
endif()
add_custom_command(
TARGET benchmark
POST_BUILD
COMMAND ${TARGET_NAME}
COMMENT "Running benchmark: ${NAME}"
USES_TERMINAL
)
endfunction()
function(add_benchmarks)
cmake_parse_arguments(
PARSED "" "" "NAMES;LIBRARIES" ${ARGN}
)
foreach(NAME ${PARSED_NAMES})
add_benchmark(${NAME} benchmark)
if(PARSED_LIBRARIES)
target_link_libraries(benchmark_${NAME} PRIVATE ${PARSED_LIBRARIES})
endif()
endforeach()
endfunction()
@@ -0,0 +1,92 @@
include(CheckCXXSourceCompiles)
include(CheckTypeSize)
cmake_push_check_state(RESET)
# Check whether the compiler supports the __popcnt64() intrinsic
check_cxx_source_compiles("
#include <intrin.h>
int main(void) {
unsigned long long a = 0xDEADBEEF;
volatile unsigned long long b;
b = __popcnt64(a);
return 0;
}
"
HAVE__POPCNT64
)
# Check whether the compiler supports the __popcnt() intrinsic
check_cxx_source_compiles("
#include <intrin.h>
int main(void) {
unsigned long a = 0xDEADBEEF;
volatile unsigned long long b;
b = __popcnt(a);
return 0;
}
"
HAVE__POPCNT
)
# Check whether the compiler supports the _BitScanForward64() intrinsic
check_cxx_source_compiles("
#include <intrin.h>
int main(void) {
unsigned long long a = 0xDEADBEEF;
unsigned long b;
volatile unsigned long c;
c = _BitScanForward64(&b, a) ? b : 64;
return 0;
}
"
HAVE__BITSCANFORWARD64
)
# Check whether the compiler supports the _BitScanForward() intrinsic
check_cxx_source_compiles("
#include <intrin.h>
int main(void) {
unsigned long a = 0xDEADBEEF, b;
volatile unsigned long c;
c = _BitScanForward(&b, a) ? b : 64;
return 0;
}
"
HAVE__BITSCANFORWARD
)
# Check whether the compiler supports the _BitScanReverse64() intrinsic
check_cxx_source_compiles("
#include <intrin.h>
int main(void) {
unsigned long long a = 0xDEADBEEF;
unsigned long b;
volatile unsigned long c;
c = _BitScanReverse64(&b, a) ? b : 64;
return 0;
}
"
HAVE__BITSCANREVERSE64
)
# Check whether the compiler supports the _BitScanReverse() intrinsic
check_cxx_source_compiles("
#include <intrin.h>
int main(void) {
unsigned long a = 0xDEADBEEF, b;
volatile unsigned long c;
c = _BitScanReverse(&b, a) ? b : 64;
return 0;
}
"
HAVE__BITSCANREVERSE
)
cmake_pop_check_state()
@@ -0,0 +1,131 @@
include(CheckCCompilerFlag)
# Enable POSIX features. This needs to be set here instead of in source files so
# that it affects CMake-based feature tests.
#
# See:
# - https://pubs.opengroup.org/onlinepubs/007904875/functions/xsh_chap02_02.html
# - https://www.gnu.org/software/libc/manual/html_node/Feature-Test-Macros.html
add_compile_definitions(_POSIX_C_SOURCE=200809L)
# On some Apple systems, with some compilers, defining _POSIX_C_SOURCE causes compilation
# failures when including C++ headers. Defining _DARWIN_C_SOURCE explicitly usually fixes
# this. Refs: https://trac.macports.org/ticket/60655 and https://trac.macports.org/ticket/73145
# This is claimed to be due to _POSIX_C_SOURCE disabling APIs that C++ headers rely on
# on some systems. _DARWIN_C_SOURCE re-enables these APIs, but _GNU_SOURCE alone does not
# necessarily do so. Using different global defined for C and C++ is problematic with CMake,
# so instead of restricting _POSIX_C_SOURCE to C, we define _DARWIN_C_SOURCE.
if(APPLE)
add_compile_definitions(_DARWIN_C_SOURCE)
endif()
if(MSVC)
add_compile_options(/FS)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS) # necessary to compile for UWP
endif()
if(NOT MSVC)
# Even though we will later use 'no-unknown-warning-option', we perform the test for
# 'unknown-warning-option', without the 'no-' prefix. This is necessary because GCC
# will accept any warning option starting with 'no-', and will not error, yet it still
# prints a message about the unrecognized option.
check_c_compiler_flag("-Wunknown-warning-option" COMPILER_SUPPORTS_UNKNOWN_WARNING_OPTION_FLAG)
endif()
set(
IGRAPH_WARNINGS_AS_ERRORS ON CACHE BOOL
"Treat warnings as errors with GCC-like compilers"
)
option(FORCE_COLORED_OUTPUT "Always produce ANSI-colored output (GNU/Clang only)." FALSE)
if(FORCE_COLORED_OUTPUT)
if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
add_compile_options(-fdiagnostics-color=always)
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_compile_options(-fcolor-diagnostics)
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang")
add_compile_options(-fcolor-diagnostics)
endif()
endif()
macro(use_all_warnings TARGET_NAME)
if(MSVC)
target_compile_options(${TARGET_NAME} PRIVATE
/W4 # enable most warnings, then disable:
/wd4244 # 'conversion' conversion from 'type1' to 'type2', possible loss of data
/wd4267 # 'var' : conversion from 'size_t' to 'type', possible loss of data
/wd4996 # deprecated functions, e.g. 'sprintf': This function or variable may be unsafe. Consider using sprintf_s instead.
/wd4456 # declaration of 'identifier' hides previous local declaration
/wd4800 # forcing value to 'true' or 'false' (performance warning)
/wd4204 # nonstandard extension used: non-constant aggregate initializer
/wd4701 # potentially uninitialized local variable
/wd4221 # nonstandard extension used: '...': cannot be initialized using address of automatic variable '...'
/wd4127 # conditional expression is constant
/wd4702 # unreachable code
)
else()
# Notes:
# GCC does not complain when encountering an unsupported "no"-prefixed warning option such as -Wno-foo.
# Clang does complain, but these complaints can be silenced with -Wno-unknown-warning-option.
# Therefore it is generally safe to use -Wno-... options that are only supported by recent GCC/Clang.
target_compile_options(${TARGET_NAME} PRIVATE
# GCC-style compilers:
$<$<C_COMPILER_ID:GCC,Clang,AppleClang,Intel,IntelLLVM>:
$<$<BOOL:${IGRAPH_WARNINGS_AS_ERRORS}>:-Werror>
-Wall -Wextra -pedantic
-Wstrict-prototypes
-Wno-unused-function -Wno-unused-parameter -Wno-unused-but-set-variable -Wno-sign-compare -Wno-constant-logical-operand
>
$<$<BOOL:${COMPILER_SUPPORTS_UNKNOWN_WARNING_OPTION_FLAG}>:-Wno-unknown-warning-option>
# Intel compiler:
$<$<C_COMPILER_ID:Intel>:
# disable #279: controlling expression is constant; affecting assert(condition && "message")
# disable #592: variable "var" is used before its value is set; affecting IGRAPH_UNUSED
# disable #10148: warning option not supported, as a replacement for -Wno-unknown-warning-option
-wd279 -wd592 -diag-disable=remark -diag-disable=10148
>
# Intel LLVM:
$<$<C_COMPILER_ID:IntelLLVM>:
-fp-model=precise # The default 'fast' mode is not compatible with igraph's extensive use of NaN/Inf
>
)
endif()
endmacro()
# Helper function to add preprocesor definition of IGRAPH_FILE_BASENAME
# to pass the filename without directory path for debugging use.
#
# Example:
#
# define_file_basename_for_sources(my_target)
#
# Will add -DIGRAPH_FILE_BASENAME="filename" for each source file depended
# on by my_target, where filename is the name of the file.
#
# Source: https://stackoverflow.com/a/27990434/156771
function(define_file_basename_for_sources targetname)
get_target_property(source_files "${targetname}" SOURCES)
get_target_property(source_dir "${targetname}" SOURCE_DIR)
foreach(sourcefile ${source_files})
# Turn relative paths into absolute
get_filename_component(source_full_path "${sourcefile}" ABSOLUTE BASE_DIR "${source_dir}")
# Figure out whether the relative path from the source or the build folder
# is shorter
file(RELATIVE_PATH source_rel_path "${PROJECT_SOURCE_DIR}" "${source_full_path}")
file(RELATIVE_PATH binary_rel_path "${PROJECT_BINARY_DIR}" "${source_full_path}")
string(LENGTH "${source_rel_path}" source_rel_path_length)
string(LENGTH "${binary_rel_path}" binary_rel_path_length)
if(binary_rel_path_length LESS source_rel_path_length)
set(basename "${binary_rel_path}")
else()
set(basename "${source_rel_path}")
endif()
# Add the IGRAPH_FILE_BASENAME=filename compile definition to the source file
set_property(
SOURCE "${sourcefile}" APPEND
PROPERTY COMPILE_DEFINITIONS "IGRAPH_FILE_BASENAME=\"${basename}\""
)
endforeach()
endfunction()
@@ -0,0 +1,87 @@
# Custom CPack install script that allows us to whitelist files to be copied
# to the tarball from the root directory, instead of copying the entire root
# directory recursively
if(CPACK_SOURCE_INSTALLED_DIRECTORIES)
# Make sure that the parser sources are built
execute_process(
COMMAND "${CMAKE_COMMAND}"
--build "${CPACK_PACKAGE_DIRECTORY}"
--target parsersources
RESULT_VARIABLE EXIT_CODE
)
if(NOT EXIT_CODE EQUAL 0)
message(FATAL_ERROR "Failed to build the parser sources.")
endif()
# Generate a version file in the build folder if we don't have one in the
# source folder
if(EXISTS "${SOURCE_DIR}/IGRAPH_VERSION")
set(IGRAPH_VERSION_FILE "${SOURCE_DIR}/IGRAPH_VERSION")
else()
execute_process(
COMMAND "${CMAKE_COMMAND}"
--build "${CPACK_PACKAGE_DIRECTORY}"
--target versionfile
RESULT_VARIABLE EXIT_CODE
)
if(NOT EXIT_CODE EQUAL 0)
message(FATAL_ERROR "Failed to determine the version number of igraph that is being packaged.")
endif()
set(IGRAPH_VERSION_FILE "${CPACK_PACKAGE_DIRECTORY}/IGRAPH_VERSION")
endif()
list(GET CPACK_BUILD_SOURCE_DIRS 0 SOURCE_DIR)
# This branch runs only if CPack generates the source package, and within
# this branch, CMAKE_CURRENT_BINARY_DIR refers to the root of the staging
# area where the tarball is assembled
file(GLOB FILES_TO_COPY "${SOURCE_DIR}/*.md")
file(
INSTALL ${FILES_TO_COPY}
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}"
)
file(
INSTALL
"${SOURCE_DIR}/AUTHORS"
"${SOURCE_DIR}/CMakeLists.txt"
"${SOURCE_DIR}/CONTRIBUTORS.txt"
"${SOURCE_DIR}/COPYING"
"${SOURCE_DIR}/ChangeLog"
"${SOURCE_DIR}/INSTALL"
"${SOURCE_DIR}/NEWS"
"${SOURCE_DIR}/ONEWS"
"${SOURCE_DIR}/igraph.pc.in"
"${IGRAPH_VERSION_FILE}"
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}"
)
file(
INSTALL
"${SOURCE_DIR}/src/config.h.in"
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/src"
)
file(
INSTALL
"${CPACK_PACKAGE_DIRECTORY}/src/io/parsers"
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/src/io"
)
file(
INSTALL
"${SOURCE_DIR}/tools/removeexamples.py"
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/tools"
)
file(
INSTALL
"${SOURCE_DIR}/tools/strip_licenses_from_examples.py"
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/tools"
)
file(
INSTALL
"${CPACK_PACKAGE_DIRECTORY}/doc/html"
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/doc"
)
file(
INSTALL
"${CPACK_PACKAGE_DIRECTORY}/doc/igraph-docs.info"
DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/doc"
)
endif()
@@ -0,0 +1,8 @@
# CMake script that generates the IGRAPH_VERSION file in the build folder
#
# Script variables that need to be set before calling it via "cmake -P":
#
# * IGRAPH_VERSION should be set to the exact version number
# * VERSION_FILE_PATH should be set to the name of the version file
FILE(WRITE "${VERSION_FILE_PATH}" "${IGRAPH_VERSION}")
@@ -0,0 +1,7 @@
set(
IGRAPH_VERIFY_FINALLY_STACK
""
CACHE
BOOL
"Verify that the 'finally' stack is cleaned up properly. Useful only in debugging; do not use in production."
)
@@ -0,0 +1,171 @@
include(helpers)
include(CheckSymbolExists)
include(CMakePushCheckState)
# The threading library is not needed for igraph itself, but might be needed
# for tests
include(FindThreads)
macro(find_dependencies)
# Declare the list of dependencies that _may_ be vendored
set(VENDORABLE_DEPENDENCIES BLAS GLPK LAPACK ARPACK GMP PLFIT INFOMAP)
# Declare optional dependencies associated with IGRAPH_..._SUPPORT flags
# Note that GLPK and INFOMAP are both vendorable and optional
set(OPTIONAL_DEPENDENCIES GLPK OpenMP INFOMAP)
# Declare configuration options for dependencies
tristate(IGRAPH_USE_INTERNAL_GMP "Compile igraph with internal Mini-GMP" AUTO)
tristate(IGRAPH_USE_INTERNAL_ARPACK "Compile igraph with internal ARPACK" AUTO)
tristate(IGRAPH_USE_INTERNAL_BLAS "Compile igraph with internal BLAS" AUTO)
tristate(IGRAPH_USE_INTERNAL_GLPK "Compile igraph with internal GLPK" AUTO)
tristate(IGRAPH_USE_INTERNAL_LAPACK "Compile igraph with internal LAPACK" AUTO)
tristate(IGRAPH_USE_INTERNAL_PLFIT "Compile igraph with internal plfit" AUTO)
# Infomap currently does not support being built as an external library, so will
# only be supported through the internal vendored build
set(IGRAPH_USE_INTERNAL_INFOMAP ON)
# Declare dependencies
set(REQUIRED_DEPENDENCIES "")
set(OPTIONAL_DEPENDENCIES FLEX BISON OpenMP)
set(VENDORED_DEPENDENCIES "")
# Declare minimum supported version for some dependencies
set(GLPK_VERSION_MIN "4.57") # 4.57 is the first version providing glp_on_error()
set(LIBXML2_VERSION_MIN "2.7.4") # 2.7.4 is the first version providing xmlStructuredErrorContext
set(PLFIT_VERSION_MIN "0.9.3")
# Extend dependencies depending on whether we will be using the vendored
# copies or not
foreach(DEPENDENCY ${VENDORABLE_DEPENDENCIES})
string(TOUPPER "${DEPENDENCY}" LIBNAME_UPPER)
if(IGRAPH_USE_INTERNAL_${LIBNAME_UPPER} STREQUAL "AUTO")
find_package(${DEPENDENCY} ${${DEPENDENCY}_VERSION_MIN} QUIET)
if(${LIBNAME_UPPER}_FOUND)
set(IGRAPH_USE_INTERNAL_${LIBNAME_UPPER} OFF)
else()
set(IGRAPH_USE_INTERNAL_${LIBNAME_UPPER} ON)
endif()
endif()
if(IGRAPH_USE_INTERNAL_${LIBNAME_UPPER})
list(APPEND VENDORED_DEPENDENCIES ${DEPENDENCY})
else()
list(APPEND REQUIRED_DEPENDENCIES ${DEPENDENCY})
endif()
endforeach()
# For optional dependencies, figure out whether we should attempt to
# link to them based on the value of the IGRAPH_..._SUPPORT option
foreach(DEPENDENCY ${OPTIONAL_DEPENDENCIES})
string(TOUPPER "${DEPENDENCY}" LIBNAME_UPPER)
if(IGRAPH_${LIBNAME_UPPER}_SUPPORT STREQUAL "AUTO")
find_package(${DEPENDENCY} ${${DEPENDENCY}_VERSION_MIN} QUIET)
if(${LIBNAME_UPPER}_FOUND)
set(IGRAPH_${LIBNAME_UPPER}_SUPPORT ON)
else()
set(IGRAPH_${LIBNAME_UPPER}_SUPPORT OFF)
endif()
endif()
endforeach()
# GraphML support is treated separately because the library name is different
if(IGRAPH_GRAPHML_SUPPORT STREQUAL "AUTO")
find_package(LibXml2 ${LIBXML2_VERSION_MIN} QUIET)
if(LibXml2_FOUND)
set(IGRAPH_GRAPHML_SUPPORT ON)
else()
set(IGRAPH_GRAPHML_SUPPORT OFF)
endif()
endif()
if(NOT IGRAPH_GLPK_SUPPORT)
if(IGRAPH_USE_INTERNAL_GLPK)
list(REMOVE_ITEM VENDORED_DEPENDENCIES GLPK)
else()
list(REMOVE_ITEM REQUIRED_DEPENDENCIES GLPK)
endif()
endif()
if(NOT IGRAPH_INFOMAP_SUPPORT)
list(REMOVE_ITEM VENDORED_DEPENDENCIES INFOMAP)
endif()
if(IGRAPH_GRAPHML_SUPPORT)
list(APPEND REQUIRED_DEPENDENCIES LibXml2)
endif()
# Find dependencies
foreach(DEPENDENCY ${REQUIRED_DEPENDENCIES} ${OPTIONAL_DEPENDENCIES})
list(FIND REQUIRED_DEPENDENCIES "${DEPENDENCY}" INDEX)
set(NEED_THIS_DEPENDENCY NO)
if(INDEX GREATER_EQUAL 0)
# This is a required dependency, search for it unconditionally. Do
# not use REQUIRED; we will report errors in a single batch at the end
# of the configuration process
set(NEED_THIS_DEPENDENCY YES)
else()
# This is an optional dependency, search for it only if the user did not
# turn it off explicitly
string(TOUPPER "${DEPENDENCY}" LIBNAME_UPPER)
if(NOT DEFINED IGRAPH_${LIBNAME_UPPER}_SUPPORT)
set(NEED_THIS_DEPENDENCY YES)
elseif(IGRAPH_${LIBNAME_UPPER}_SUPPORT)
set(NEED_THIS_DEPENDENCY YES)
endif()
endif()
if(NEED_THIS_DEPENDENCY AND NOT DEFINED ${DEPENDENCY}_FOUND)
find_package(${DEPENDENCY} ${${DEPENDENCY}_VERSION_MIN})
endif()
endforeach()
# Override libraries of vendored dependencies even if they were somehow
# detected above
foreach(DEPENDENCY ${VENDORED_DEPENDENCIES})
string(TOUPPER "${DEPENDENCY}" LIBNAME_UPPER)
string(TOLOWER "${DEPENDENCY}" LIBNAME_LOWER)
if(IGRAPH_USE_INTERNAL_${LIBNAME_UPPER})
set(${LIBNAME_UPPER}_LIBRARIES "")
set(${LIBNAME_UPPER}_FOUND 1)
set(${LIBNAME_UPPER}_IS_VENDORED 1)
set(INTERNAL_${LIBNAME_UPPER} 1)
endif()
endforeach()
# Export some aliases that will be used in config.h
set(HAVE_GLPK ${GLPK_FOUND})
set(HAVE_INFOMAP ${INFOMAP_FOUND})
set(HAVE_GMP ${GMP_FOUND})
set(HAVE_LIBXML ${LIBXML2_FOUND})
# Check whether we need to link to the math library
if(NOT DEFINED CACHE{NEED_LINKING_AGAINST_LIBM})
cmake_push_check_state()
set(CMAKE_REQUIRED_QUIET ON)
check_symbol_exists(sinh "math.h" SINH_FUNCTION_EXISTS)
if(NOT SINH_FUNCTION_EXISTS)
unset(SINH_FUNCTION_EXISTS CACHE)
list(APPEND CMAKE_REQUIRED_LIBRARIES m)
check_symbol_exists(sinh "math.h" SINH_FUNCTION_EXISTS)
if(SINH_FUNCTION_EXISTS)
set(NEED_LINKING_AGAINST_LIBM True CACHE BOOL "" FORCE)
else()
message(FATAL_ERROR "Failed to figure out how to link to the math library on this platform")
endif()
endif()
unset(SINH_FUNCTION_EXISTS CACHE)
cmake_pop_check_state()
endif()
if(NEED_LINKING_AGAINST_LIBM)
find_library(MATH_LIBRARY m)
endif()
mark_as_advanced(MATH_LIBRARY)
mark_as_advanced(NEED_LINKING_AGAINST_LIBM)
endmacro()
@@ -0,0 +1,26 @@
include(helpers)
include(tls)
include(lto)
option(IGRAPH_GLPK_SUPPORT "Compile igraph with GLPK support" ON)
option(IGRAPH_INFOMAP_SUPPORT "Compile igraph with Infomap support" ON)
tristate(IGRAPH_GRAPHML_SUPPORT "Compile igraph with GraphML support" AUTO)
tristate(IGRAPH_OPENMP_SUPPORT "Use OpenMP for parallelization" AUTO)
set(IGRAPH_INTEGER_SIZE AUTO CACHE STRING "Set size of igraph integers")
set_property(CACHE IGRAPH_INTEGER_SIZE PROPERTY STRINGS AUTO 32 64)
if(IGRAPH_INTEGER_SIZE STREQUAL AUTO)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(IGRAPH_INTEGER_SIZE 64)
else()
set(IGRAPH_INTEGER_SIZE 32)
endif()
endif()
option(FLEX_KEEP_LINE_NUMBERS "Keep references to the original line numbers in generated Flex/Bison parser files" OFF)
mark_as_advanced(FLEX_KEEP_LINE_NUMBERS)
option(BUILD_FUZZING "Build fuzz targets and enable fuzzer instrumentation" OFF)
mark_as_advanced(BUILD_FUZZING)
@@ -0,0 +1,16 @@
function(add_fuzzer NAME)
set(TARGET_NAME fuzzer_${NAME})
add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL ${PROJECT_SOURCE_DIR}/fuzzing/${NAME}.cpp)
add_dependencies(build_fuzzers ${TARGET_NAME})
target_link_libraries(${TARGET_NAME} PRIVATE igraph)
# The -fsanitize=fuzzer-no-link is already added by the top-level CMakeLists.txt
# for general fuzzer instrumentation. Additionally, we need -fsanitize=fuzzer
# for the fuzz targets, which do not contain a main() function, to link in the
# fuzz driver. See https://llvm.org/docs/LibFuzzer.html
target_link_options(${TARGET_NAME} PRIVATE -fsanitize=fuzzer)
endfunction()
@@ -0,0 +1,46 @@
# Creates a ctags-compatible tags file from a set of XML files by extracting
# the IDs found in the XML files.
#
# Parameters of the script:
#
# - INPUT_FILES: list of input files to process, with absolute pathnames
# - OUTPUT_FILE: the output file to write the tags into
string(REPLACE " " ";" INPUT_FILE_LIST "${INPUT_FILES}")
set(EXTRACTED_IDS "")
foreach(INPUT_FILE ${INPUT_FILE_LIST})
file(READ "${INPUT_FILE}" CONTENTS)
# Replace newlines with semicolons. This is a hack and we should escape
# semicolons first if we wanted to do this properly; however, here we are
# only interested in XML IDs and they don't have semicolons
string(REPLACE "\n" ";" LINES "${CONTENTS}")
foreach(_line ${LINES})
string(REGEX MATCHALL "id=\"[^-\"]*\"" MATCH_RESULT "${_line}")
if(MATCH_RESULT)
foreach(MATCH ${MATCH_RESULT})
string(REGEX REPLACE "id=\"(.*)\"" "\\1" EXTRACTED_ID "${MATCH}")
list(APPEND EXTRACTED_IDS "${EXTRACTED_ID}")
endforeach()
endif()
endforeach()
endforeach()
list(SORT EXTRACTED_IDS)
string(REPLACE ";" "\t\t\n" TAGS_OUTPUT "${EXTRACTED_IDS}")
string(APPEND TAGS_OUTPUT "\t\t\n")
string(SHA1 TAGS_OUTPUT_HASH "${TAGS_OUTPUT}")
# Update the output file only if it changed; this prevents CMake from calling
# source-highlight if there is no point in rebuilding the highlighted
# source files
if(EXISTS "${OUTPUT_FILE}")
file(SHA1 "${OUTPUT_FILE}" OUTPUT_FILE_HASH)
if(NOT "${OUTPUT_FILE_HASH}" STREQUAL "${TAGS_OUTPUT_HASH}")
file(WRITE "${OUTPUT_FILE}" "${TAGS_OUTPUT}")
endif()
else()
file(WRITE "${OUTPUT_FILE}" "${TAGS_OUTPUT}")
endif()
@@ -0,0 +1,6 @@
macro(tristate OPTION_NAME DESCRIPTION DEFAULT_VALUE)
set(${OPTION_NAME} "${DEFAULT_VALUE}" CACHE STRING "${DESCRIPTION}")
set_property(CACHE ${OPTION_NAME} PROPERTY STRINGS AUTO ON OFF)
endmacro()
include(PadString)
@@ -0,0 +1,54 @@
include(CheckCSourceRuns)
cmake_push_check_state(RESET)
# Check whether IEEE754 doubles are laid out in little-endian order. We do this
# only when not cross-compiling; during cross-compilation, the host architecture
# might have different endianness conventions than the target, and we are running
# the test on the host here
if(CMAKE_CROSSCOMPILING AND NOT CMAKE_CROSSCOMPILING_EMULATOR)
# If we are cross-compiling and we have no emulator, let's just assume that
# IEEE754 doubles use the same endianness as uint64_t
set(IEEE754_DOUBLE_ENDIANNESS_MATCHES YES)
message(WARNING "\
igraph is being cross-compiled, therefore we cannot validate whether the \
endianness of IEEE754 doubles is the same as the endianness of uint64_t. \
Most likely it is, unless you are compiling for some esoteric platform, \
in which case you need make sure that this is the case on your own.\
")
else()
if(NOT DEFINED CACHE{IEEE754_DOUBLE_ENDIANNESS_MATCHES})
try_run(
IEEE754_DOUBLE_ENDIANNESS_TEST_EXIT_CODE
IEEE754_DOUBLE_ENDIANNESS_TEST_COMPILES
${CMAKE_BINARY_DIR}
${PROJECT_SOURCE_DIR}/etc/cmake/ieee754_endianness_check.c
RUN_OUTPUT_VARIABLE IEEE754_DOUBLE_ENDIANNESS_TEST_RESULT
)
# Strip trailing newline, which is necessary on some platforms (such as node.js)
# to complete printing the output.
string(STRIP "${IEEE754_DOUBLE_ENDIANNESS_TEST_RESULT}" IEEE754_DOUBLE_ENDIANNESS_TEST_RESULT)
if(IEEE754_DOUBLE_ENDIANNESS_TEST_EXIT_CODE EQUAL 0)
if(IEEE754_DOUBLE_ENDIANNESS_TEST_RESULT STREQUAL "OK")
set(TEST_RESULT YES)
else()
set(TEST_RESULT NO)
endif()
else()
message(FATAL_ERROR "IEEE754 double endianness test terminated abnormally.")
endif()
set(
IEEE754_DOUBLE_ENDIANNESS_MATCHES ${TEST_RESULT} CACHE BOOL
"Specifies whether the endianness of IEEE754 doubles is the same as the endianness of uint64_t."
FORCE
)
mark_as_advanced(IEEE754_DOUBLE_ENDIANNESS_MATCHES)
endif()
endif()
cmake_pop_check_state()
if(NOT IEEE754_DOUBLE_ENDIANNESS_MATCHES)
message(FATAL_ERROR "igraph only supports platforms where IEEE754 doubles have the same endianness as uint64_t.")
endif()
@@ -0,0 +1,24 @@
/* Checks whether the endianness of IEEE754 doubles matches the endianness of
* uint64_t on the target system. This is needed to ensure that the trick we
* employ in igraph_rng_get_unif01() works. */
#include <stdint.h>
#include <stdio.h>
union {
uint64_t as_uint64_t;
double as_double;
} value;
int main(void) {
value.as_uint64_t = 4841376218035192321ULL;
if (value.as_double == 4510218239279617.0) {
/* endianness of uint64_t and double match */
printf("OK\n");
}
/* We always return 0, even for a negative result, this is because we
* need to tell on the CMake side whether a compiler misconfiguration
* aborted our program, which can then be detected from a nonzero exit
* code. */
return 0;
}
@@ -0,0 +1,40 @@
# igraph-config.cmake
#
# igraph CMake package
#
# The following variables are set:
#
# - IGRAPH_VERSION - The igraph version string.
# - IGRAPH_INTEGER_SIZE - The integer size igraph was configured with (32 or 64).
# - IGRAPH_GLPK_SUPPORT - Whether igraph was compiled with GLPK support.
# - IGRAPH_GRAPHML_SUPPORT - Whether igraph was compiled with GraphML support.
#
set(IGRAPH_VERSION "@PACKAGE_VERSION_BASE@")
set(IGRAPH_INTEGER_SIZE @IGRAPH_INTEGER_SIZE@)
set(IGRAPH_GLPK_SUPPORT @IGRAPH_GLPK_SUPPORT@)
set(IGRAPH_GRAPHML_SUPPORT @IGRAPH_GRAPHML_SUPPORT@)
@PACKAGE_INIT@
include("${CMAKE_CURRENT_LIST_DIR}/igraph-targets.cmake")
# Check whether C++ support is enabled; this is needed to ensure that programs
# that are dependent on igraph will get linked with the C++ linker and not the
# "plain" C linker
get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES)
if("CXX" IN_LIST LANGUAGES)
# This is okay
else()
message(FATAL_ERROR "Please enable C++ support in your project if you are linking to igraph.")
endif()
# Turn on CMP0012 because the following if() conditionals will use "ON" and
# "OFF" verbatim and they must be evaluated as booleans
cmake_policy(PUSH)
cmake_policy(SET CMP0012 NEW)
if(@IGRAPH_OPENMP_SUPPORT@)
find_package(OpenMP)
endif()
cmake_policy(POP)
check_required_components(igraph)
@@ -0,0 +1,23 @@
include(helpers)
tristate(IGRAPH_ENABLE_LTO "Enable link-time optimization" OFF)
include(CheckIPOSupported)
if(IGRAPH_ENABLE_LTO)
# this matches both ON and AUTO
check_ipo_supported(RESULT IPO_SUPPORTED OUTPUT IPO_NOT_SUPPORTED_REASON)
if(IGRAPH_ENABLE_LTO STREQUAL "AUTO")
# autodetection
set(IGRAPH_ENABLE_LTO ${IPO_SUPPORTED})
if(IPO_SUPPORTED)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif()
elseif(IPO_SUPPORTED)
# user wanted LTO and the compiler supports it
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
else()
# user wanted LTO and the compiler does not support it
message(FATAL_ERROR "Link-time optimization not supported on this compiler")
endif()
endif()
@@ -0,0 +1,70 @@
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "igraph library")
set(CPACK_PACKAGE_HOMEPAGE_URL "https://igraph.org")
set(CPACK_PACKAGE_VENDOR "The igraph development team")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_SOURCE_DIR}/COPYING")
if(TARGET html AND TARGET info)
# Alias "dist" to "package_source"
add_custom_target(dist
COMMAND "${CMAKE_COMMAND}"
--build "${CMAKE_BINARY_DIR}"
--target package_source
VERBATIM
USES_TERMINAL
)
# Add dependencies to "dist"
add_dependencies(dist html info)
else()
add_custom_target(dist
COMMAND "${CMAKE_COMMAND}" -E false
COMMENT
"Cannot build source tarball since the HTML or the Texinfo documentation was not built."
VERBATIM
USES_TERMINAL
)
endif()
#############################################################################
## Configuration of the source package
#############################################################################
# Set source package name and format
set(CPACK_SOURCE_PACKAGE_FILE_NAME "igraph-${PACKAGE_VERSION}")
set(CPACK_SOURCE_GENERATOR "TGZ")
# Declare what to include in the source tarball. Unfortunately we can only
# declare full directories here, not individual files.
set(
CPACK_SOURCE_INSTALLED_DIRECTORIES
"${CMAKE_SOURCE_DIR}/doc;/doc"
"${CMAKE_SOURCE_DIR}/etc/cmake;/etc/cmake"
"${CMAKE_SOURCE_DIR}/examples;/examples"
"${CMAKE_SOURCE_DIR}/include;/include"
"${CMAKE_SOURCE_DIR}/interfaces;/interfaces"
"${CMAKE_SOURCE_DIR}/msvc/include;/msvc/include"
"${CMAKE_SOURCE_DIR}/src;/src"
"${CMAKE_SOURCE_DIR}/tests;/tests"
"${CMAKE_SOURCE_DIR}/vendor;/vendor"
)
# CPack is pretty dumb as it can only copy full directories (sans the ignored
# files) to the target tarball by default. In some cases it is easier to
# whitelist files to be copied; we use CPACK_INSTALL_SCRIPT for that.
set(CPACK_INSTALL_SCRIPT "${CMAKE_SOURCE_DIR}/etc/cmake/cpack_install_script.cmake")
# Ignore the build and all hidden folders
set(
CPACK_SOURCE_IGNORE_FILES
"\\\\..*/"
"\\\\.l$"
"\\\\.y$"
"${CMAKE_SOURCE_DIR}/build"
)
#############################################################################
## Now we can include CPack
#############################################################################
include(CPack)
@@ -0,0 +1,75 @@
# Helper functions for generating a nicely formatted igraph.pc file from
# igraph.pc.in
include(JoinPaths)
include(CheckCXXSymbolExists)
# Converts the name of a library file (or framework on macOS) into an
# appropriate linker flag (-lsomething or -framework something.framework).
# Returns the input intact if its extension does not look like a shared or
# static library extension.
function(convert_library_file_to_flags output_variable input)
get_filename_component(input_filename ${input} NAME_WE)
get_filename_component(input_extension ${input} LAST_EXT)
if(input_extension STREQUAL ${CMAKE_SHARED_LIBRARY_SUFFIX} OR input_extension STREQUAL ${CMAKE_STATIC_LIBRARY_SUFFIX})
string(REGEX REPLACE "^${CMAKE_SHARED_LIBRARY_PREFIX}" "" input_stripped ${input_filename})
set("${output_variable}" "-l${input_stripped}" PARENT_SCOPE)
elseif(APPLE AND input_extension STREQUAL ".framework")
set("${output_variable}" "-framework ${input_filename}" PARENT_SCOPE)
else()
set("${output_variable}" "${input}" PARENT_SCOPE)
endif()
endfunction()
if(MATH_LIBRARY)
set(PKGCONFIG_LIBS_PRIVATE "-lm")
else()
set(PKGCONFIG_LIBS_PRIVATE "")
endif()
set(PKGCONFIG_REQUIRES_PRIVATE "")
if(NOT MSVC)
check_cxx_symbol_exists(_LIBCPP_VERSION "vector" USING_LIBCXX)
check_cxx_symbol_exists(__GLIBCXX__ "vector" USING_LIBSTDCXX)
if(USING_LIBCXX)
set(PKGCONFIG_LIBS_PRIVATE "${PKGCONFIG_LIBS_PRIVATE} -lc++")
elseif(USING_LIBSTDCXX)
set(PKGCONFIG_LIBS_PRIVATE "${PKGCONFIG_LIBS_PRIVATE} -lstdc++")
endif()
endif()
if(IGRAPH_GRAPHML_SUPPORT)
set(PKGCONFIG_REQUIRES_PRIVATE "${PKGCONFIG_REQUIRES_PRIVATE} libxml-2.0")
endif()
if(NOT IGRAPH_USE_INTERNAL_GMP)
set(PKGCONFIG_LIBS_PRIVATE "${PKGCONFIG_LIBS_PRIVATE} -lgmp")
endif()
if(NOT IGRAPH_USE_INTERNAL_BLAS)
set(PKGCONFIG_LIBS_PRIVATE "${PKGCONFIG_LIBS_PRIVATE} -lblas")
endif()
if(IGRAPH_GLPK_SUPPORT AND NOT IGRAPH_USE_INTERNAL_GLPK)
set(PKGCONFIG_LIBS_PRIVATE "${PKGCONFIG_LIBS_PRIVATE} -lglpk")
endif()
if(NOT IGRAPH_USE_INTERNAL_LAPACK)
set(PKGCONFIG_LIBS_PRIVATE "${PKGCONFIG_LIBS_PRIVATE} -llapack")
endif()
if(NOT IGRAPH_USE_INTERNAL_ARPACK)
set(PKGCONFIG_LIBS_PRIVATE "${PKGCONFIG_LIBS_PRIVATE} -larpack")
endif()
if(NOT IGRAPH_USE_INTERNAL_PLFIT)
set(PKGCONFIG_LIBS_PRIVATE "${PKGCONFIG_LIBS_PRIVATE} -lplfit")
endif()
if(IGRAPH_OPENMP_SUPPORT AND OpenMP_FOUND)
foreach(CURRENT_LIB ${OpenMP_C_LIB_NAMES})
convert_library_file_to_flags(CURRENT_LIB "${OpenMP_${CURRENT_LIB}_LIBRARY}")
set(PKGCONFIG_LIBS_PRIVATE "${PKGCONFIG_LIBS_PRIVATE} ${CURRENT_LIB}")
endforeach()
endif()
join_paths(PKGCONFIG_LIBDIR "\${exec_prefix}" "${CMAKE_INSTALL_LIBDIR}")
join_paths(PKGCONFIG_INCLUDEDIR "\${prefix}" "${CMAKE_INSTALL_INCLUDEDIR}")
configure_file(
${PROJECT_SOURCE_DIR}/igraph.pc.in
${PROJECT_BINARY_DIR}/igraph.pc
@ONLY
)
@@ -0,0 +1,73 @@
# Runs a legacy autotools-based test with a file containing the expected output
#
# Parameters of the script:
#
# - TEST_EXECUTABLE: full path of the compiled test executable
# - EXPECTED_OUTPUT_FILE: full path of the file containing the expected output
# - OBSERVED_OUTPUT_FILE: full path of the file where the observed output
# can be written
# - DIFF_FILE: full path of the file where the differences between the expectd
# and the observed output should be written
# - DIFF_TOOL: full path to a "diff" tool on the system of the user, if present
# - FC_TOOL: full path to a "fc" tool on the system of the user, if present
# - IGRAPH_VERSION: version string of igraph that should be replaced in
# expected outputs
get_filename_component(WORK_DIR ${EXPECTED_OUTPUT_FILE} DIRECTORY)
execute_process(
COMMAND ${CROSSCOMPILING_EMULATOR} ${TEST_EXECUTABLE}
WORKING_DIRECTORY ${WORK_DIR}
RESULT_VARIABLE ERROR_CODE
OUTPUT_VARIABLE OBSERVED_OUTPUT
)
if(ERROR_CODE EQUAL 77)
message(STATUS "Test skipped")
elseif(ERROR_CODE)
set(MESSAGE "Test exited abnormally with error: ${ERROR_CODE}")
file(WRITE ${OBSERVED_OUTPUT_FILE} "${MESSAGE}\n=========================================\n${OBSERVED_OUTPUT}")
execute_process(COMMAND "${CMAKE_COMMAND}" -E cat "${OBSERVED_OUTPUT_FILE}")
file(REMOVE ${DIFF_FILE})
message(FATAL_ERROR "Exiting test.")
else()
string(REPLACE ${IGRAPH_VERSION} "\@VERSION\@" OBSERVED_OUTPUT "${OBSERVED_OUTPUT}")
file(WRITE ${OBSERVED_OUTPUT_FILE} "${OBSERVED_OUTPUT}")
execute_process(
COMMAND ${CMAKE_COMMAND} -E compare_files --ignore-eol
${EXPECTED_OUTPUT_FILE} ${OBSERVED_OUTPUT_FILE}
RESULT_VARIABLE ARE_DIFFERENT
)
if(ARE_DIFFERENT)
if(DIFF_TOOL)
execute_process(
COMMAND ${DIFF_TOOL} -u ${EXPECTED_OUTPUT_FILE} ${OBSERVED_OUTPUT_FILE}
OUTPUT_FILE ${DIFF_FILE}
)
elseif(FC_TOOL)
file(TO_NATIVE_PATH "${EXPECTED_OUTPUT_FILE}" REAL_EXPECTED_OUTPUT_FILE)
file(TO_NATIVE_PATH "${OBSERVED_OUTPUT_FILE}" REAL_OBSERVED_OUTPUT_FILE)
execute_process(
COMMAND ${FC_TOOL} /A ${REAL_EXPECTED_OUTPUT_FILE} ${REAL_OBSERVED_OUTPUT_FILE}
OUTPUT_FILE ${DIFF_FILE}
)
endif()
message(STATUS "Test case output differs from the expected output")
if(EXISTS ${DIFF_FILE})
message(STATUS "See diff below:")
message(STATUS "-------------------------------------------------------")
execute_process(COMMAND "${CMAKE_COMMAND}" -E cat "${DIFF_FILE}")
message(STATUS "-------------------------------------------------------")
else()
message(STATUS "Diff omitted; no diff tool was installed.")
endif()
message(FATAL_ERROR "Exiting test.")
else()
file(REMOVE ${DIFF_FILE})
endif()
file(REMOVE ${OBSERVED_OUTPUT_FILE})
endif()
@@ -0,0 +1,18 @@
include(CheckCXXSourceCompiles)
# Check whether the compiler supports the __builtin_add_overflow() and __builtin_mul_overflow()
# builtins. These are present in recent GCC-compatible compilers.
cmake_push_check_state(RESET)
check_cxx_source_compiles("
int main(void) {
long long a=1, b=2, c;
__builtin_add_overflow(a, b, &c);
__builtin_mul_overflow(a, b, &c);
return 0;
}
"
HAVE_BUILTIN_OVERFLOW
)
cmake_pop_check_state()
@@ -0,0 +1,88 @@
#
# Copyright (C) 2018 by George Cave - gcave@stablecoder.ca
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may not
# use this file except in compliance with the License. You may obtain a copy of
# the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under
# the License.
set(
USE_SANITIZER
""
CACHE
STRING
"Compile with a sanitizer. Options are: Address, Memory, MemoryWithOrigins, Undefined, Thread, Leak, 'Address;Undefined'"
)
function(append value)
foreach(variable ${ARGN})
set(${variable} "${${variable}} ${value}" PARENT_SCOPE)
endforeach(variable)
endfunction()
if(USE_SANITIZER)
if(UNIX)
append("-fno-omit-frame-pointer" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
if(uppercase_CMAKE_BUILD_TYPE STREQUAL "DEBUG")
append("-Og" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
endif()
if(USE_SANITIZER MATCHES "([Aa]ddress);([Uu]ndefined)"
OR USE_SANITIZER MATCHES "([Uu]ndefined);([Aa]ddress)")
message(STATUS "Building with Address, Undefined sanitizers")
append("-fsanitize=address,undefined" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
elseif("${USE_SANITIZER}" MATCHES "([Aa]ddress)")
# Optional: -fno-optimize-sibling-calls -fsanitize-address-use-after-scope
message(STATUS "Building with Address sanitizer")
append("-fsanitize=address" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
elseif(USE_SANITIZER MATCHES "([Mm]emory([Ww]ith[Oo]rigins)?)")
# Optional: -fno-optimize-sibling-calls -fsanitize-memory-track-origins=2
append("-fsanitize=memory" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
if(USE_SANITIZER MATCHES "([Mm]emory[Ww]ith[Oo]rigins)")
message(STATUS "Building with MemoryWithOrigins sanitizer")
append("-fsanitize-memory-track-origins" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
else()
message(STATUS "Building with Memory sanitizer")
endif()
elseif(USE_SANITIZER MATCHES "([Uu]ndefined)")
message(STATUS "Building with Undefined sanitizer")
append("-fsanitize=undefined" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
if(EXISTS "${BLACKLIST_FILE}")
append("-fsanitize-blacklist=${BLACKLIST_FILE}" CMAKE_C_FLAGS
CMAKE_CXX_FLAGS)
endif()
elseif(USE_SANITIZER MATCHES "([Tt]hread)")
message(STATUS "Building with Thread sanitizer")
append("-fsanitize=thread" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
elseif(USE_SANITIZER MATCHES "([Ll]eak)")
message(STATUS "Building with Leak sanitizer")
append("-fsanitize=leak" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
else()
message(
FATAL_ERROR "Unsupported value of USE_SANITIZER: ${USE_SANITIZER}")
endif()
elseif(MSVC)
if(USE_SANITIZER MATCHES "([Aa]ddress)")
message(STATUS "Building with Address sanitizer")
append("-fsanitize=address" CMAKE_C_FLAGS CMAKE_CXX_FLAGS)
else()
message(
FATAL_ERROR
"This sanitizer not yet supported in the MSVC environment: ${USE_SANITIZER}"
)
endif()
else()
message(FATAL_ERROR "USE_SANITIZER is not supported on this platform.")
endif()
endif()
@@ -0,0 +1,108 @@
function(print_bool HEADING VAR)
if(${VAR})
set(LABEL "yes")
else()
set(LABEL "no")
endif()
print_str(${HEADING} ${LABEL})
endfunction()
function(print_str HEADING LABEL)
string(LENGTH "${HEADING}" HEADING_LENGTH)
math(EXPR REMAINING_WIDTH "30 - ${HEADING_LENGTH}")
if("${LABEL}" STREQUAL "")
pad_string(PADDED ${REMAINING_WIDTH} " " "${ARGN}")
else()
pad_string(PADDED ${REMAINING_WIDTH} " " "${LABEL}")
endif()
message(STATUS "${HEADING}: ${PADDED}")
endfunction()
#############################################################################
set(ALL_DEPENDENCIES ${REQUIRED_DEPENDENCIES} ${OPTIONAL_DEPENDENCIES} ${VENDORED_DEPENDENCIES})
list(SORT ALL_DEPENDENCIES CASE INSENSITIVE)
message(STATUS " ")
message(STATUS "-----[ Build configuration ]----")
print_str("Version" "${PACKAGE_VERSION}")
print_str("CMake build type" "${CMAKE_BUILD_TYPE}" "default")
if(BUILD_SHARED_LIBS)
message(STATUS "Library type: shared")
else()
message(STATUS "Library type: static")
endif()
if(${IGRAPH_INTEGER_SIZE} STREQUAL "AUTO")
print_str("igraph_int_t size" "auto")
elseif(${IGRAPH_INTEGER_SIZE} STREQUAL 64)
print_str("igraph_int_t size" "64 bits")
elseif(${IGRAPH_INTEGER_SIZE} STREQUAL 32)
print_str("igraph_int_t size" "32 bits")
else()
print_str("igraph_int_t size" "INVALID")
endif()
if(USE_CCACHE)
if(CCACHE_PROGRAM)
message(STATUS "Compiler cache: ccache")
endif()
else()
message(STATUS "Compiler cache: disabled")
endif()
message(STATUS " ")
message(STATUS "----------[ Features ]----------")
print_bool("GLPK for optimization" IGRAPH_GLPK_SUPPORT)
print_bool("Infomap community detection" IGRAPH_INFOMAP_SUPPORT)
print_bool("Reading GraphML files" IGRAPH_GRAPHML_SUPPORT)
print_bool("Thread-local storage" IGRAPH_ENABLE_TLS)
print_bool("Link-time optimization" IGRAPH_ENABLE_LTO)
message(STATUS " ")
message(STATUS "--------[ Dependencies ]--------")
foreach(DEPENDENCY ${ALL_DEPENDENCIES})
list(FIND VENDORED_DEPENDENCIES "${DEPENDENCY}" INDEX)
if(INDEX EQUAL -1)
print_bool("${DEPENDENCY}" ${DEPENDENCY}_FOUND)
# This is a hack to skip printing Infomap, until
# support for linking to an external version is added
elseif(NOT "${DEPENDENCY}" STREQUAL "INFOMAP")
print_str("${DEPENDENCY}" "vendored")
endif()
endforeach()
message(STATUS " ")
message(STATUS "-----------[ Testing ]----------")
if(DIFF_TOOL)
print_str("Diff tool" "diff")
elseif(FC_TOOL)
print_str("Diff tool" "fc")
else()
print_str("Diff tool" "not found")
endif()
print_str("Sanitizers" "${USE_SANITIZER}" "none")
print_bool("Code coverage" IGRAPH_ENABLE_CODE_COVERAGE)
print_bool("Verify 'finally' stack" IGRAPH_VERIFY_FINALLY_STACK)
message(STATUS " ")
message(STATUS "--------[ Documentation ]-------")
print_bool("HTML" HTML_DOC_BUILD_SUPPORTED)
print_bool("PDF" PDF_DOC_BUILD_SUPPORTED)
print_bool("INFO" INFO_DOC_BUILD_SUPPORTED)
message(STATUS " ")
set(MISSING_DEPENDENCIES)
foreach(DEPENDENCY ${REQUIRED_DEPENDENCIES})
if(NOT ${DEPENDENCY}_FOUND)
list(APPEND MISSING_DEPENDENCIES ${DEPENDENCY})
endif()
endforeach()
if(MISSING_DEPENDENCIES)
list(JOIN MISSING_DEPENDENCIES ", " GLUED)
message(FATAL_ERROR "The following dependencies are missing: ${GLUED}")
else()
message(STATUS "igraph configured successfully.")
message(STATUS " ")
endif()
@@ -0,0 +1,120 @@
include(CMakeParseArguments)
find_program(DIFF_TOOL diff)
if(NOT DIFF_TOOL)
find_program(FC_TOOL fc)
endif()
function(add_legacy_test FOLDER NAME NAMESPACE)
set(TARGET_NAME ${NAMESPACE}_${NAME})
set(TEST_NAME "${NAMESPACE}::${NAME}")
add_executable(${TARGET_NAME} EXCLUDE_FROM_ALL ${PROJECT_SOURCE_DIR}/${FOLDER}/${NAME}.c)
use_all_warnings(${TARGET_NAME})
add_dependencies(build_tests ${TARGET_NAME})
# Specify linking with test_utilities *before* linking with igraph, to avoid
# duplicating libigraph.a. See https://github.com/igraph/igraph/issues/2394
if (NAMESPACE STREQUAL "test")
target_link_libraries(${TARGET_NAME} PRIVATE test_utilities)
endif()
target_link_libraries(${TARGET_NAME} PRIVATE igraph)
# Some tests depend on internal igraph headers so we also have to add src/
# to the include path even though it's not part of the public API
target_include_directories(
${TARGET_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/src ${CMAKE_BINARY_DIR}/src
)
# Some tests include cs.h from CXSparse
target_include_directories(
${TARGET_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/vendor/cs
)
if (MSVC)
# Add MSVC-specific include path for some headers that are missing on Windows
target_include_directories(${TARGET_NAME} PRIVATE ${CMAKE_SOURCE_DIR}/msvc/include)
endif()
set(EXPECTED_OUTPUT_FILE ${CMAKE_SOURCE_DIR}/${FOLDER}/${NAME}.out)
set(OBSERVED_OUTPUT_FILE ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.out)
set(DIFF_FILE ${CMAKE_CURRENT_BINARY_DIR}/${TARGET_NAME}.diff)
get_filename_component(WORK_DIR ${EXPECTED_OUTPUT_FILE} DIRECTORY)
if(EXISTS ${EXPECTED_OUTPUT_FILE})
get_property(CROSSCOMPILING_EMULATOR TARGET ${TARGET_NAME} PROPERTY CROSSCOMPILING_EMULATOR)
add_test(
NAME ${TEST_NAME}
COMMAND ${CMAKE_COMMAND}
-DTEST_EXECUTABLE=$<TARGET_FILE:${TARGET_NAME}>
-DEXPECTED_OUTPUT_FILE=${EXPECTED_OUTPUT_FILE}
-DOBSERVED_OUTPUT_FILE=${OBSERVED_OUTPUT_FILE}
-DDIFF_FILE=${DIFF_FILE}
-DDIFF_TOOL=${DIFF_TOOL}
-DFC_TOOL=${FC_TOOL}
-DIGRAPH_VERSION=${PACKAGE_VERSION}
"-DCROSSCOMPILING_EMULATOR=${CROSSCOMPILING_EMULATOR}"
-P ${CMAKE_SOURCE_DIR}/etc/cmake/run_legacy_test.cmake
)
set_property(TEST ${TEST_NAME} PROPERTY SKIP_REGULAR_EXPRESSION "Test skipped")
else()
add_test(
NAME ${TEST_NAME}
COMMAND ${TARGET_NAME}
WORKING_DIRECTORY ${WORK_DIR}
)
set_property(TEST ${TEST_NAME} PROPERTY SKIP_RETURN_CODE 77)
endif()
if (WIN32 AND BUILD_SHARED_LIBS)
# On Windows the built igraph.dll is not automatically found by the tests. We therefore
# add the dir that contains the built igraph.dll to the path environment variable
# so that igraph.dll is found when running the tests.
SET(IGRAPH_LIBDIR $<TARGET_FILE_DIR:igraph>)
# The next line is necessitated by MinGW on Windows. MinGW uses forward slashes in
# IGRAPH_LIBDIR, but we need to supply CTest with backslashes because CTest is executed
# in a cmd.exe shell. We therefore explicitly ensure that that path is transformed to a
# native path.
file(TO_NATIVE_PATH "${IGRAPH_LIBDIR}" IGRAPH_LIBDIR)
# Semicolons are used as list separators in CMake so we need to escape them in the PATH,
# otherwise the PATH envvar gets split by CMake before it passes the PATH on to CTest.
# We process each path separately to ensure it is a proper path. In particular, we need
# to ensure that a trailing backslash is not incorrectly interpreted as an escape
# character. Presumably, with cmake 3.20, this can be changed to using TO_NATIVE_PATH_LIST.
SET(TEST_PATHS)
foreach (PATH $ENV{PATH})
file(TO_NATIVE_PATH "${PATH}" CORRECT_PATH)
# Remove trailing backslash
STRING(REGEX REPLACE "\\$" "" CORRECT_PATH ${CORRECT_PATH})
list(APPEND TEST_PATHS ${CORRECT_PATH})
endforeach()
# Join all paths in a single string, separated by an escaped semi-colon.
string(JOIN "\;" CORRECT_PATHS ${TEST_PATHS})
SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES ENVIRONMENT "PATH=${IGRAPH_LIBDIR}\;${CORRECT_PATHS}" )
endif()
endfunction()
function(add_legacy_tests)
cmake_parse_arguments(
PARSED "" "FOLDER" "NAMES;LIBRARIES" ${ARGN}
)
foreach(NAME ${PARSED_NAMES})
add_legacy_test(${PARSED_FOLDER} ${NAME} test)
if(PARSED_LIBRARIES)
target_link_libraries(test_${NAME} PRIVATE ${PARSED_LIBRARIES})
endif()
endforeach()
endfunction()
function(add_examples)
cmake_parse_arguments(
PARSED "" "FOLDER" "NAMES;LIBRARIES" ${ARGN}
)
foreach(NAME ${PARSED_NAMES})
add_legacy_test(${PARSED_FOLDER} ${NAME} example)
if(PARSED_LIBRARIES)
target_link_libraries(example_${NAME} PRIVATE ${PARSED_LIBRARIES})
endif()
endforeach()
endfunction()
@@ -0,0 +1,25 @@
tristate(IGRAPH_ENABLE_TLS "Enable thread-local storage for igraph global variables" AUTO)
include(CheckTLSSupport)
check_tls_support(TLS_KEYWORD)
if(IGRAPH_ENABLE_TLS STREQUAL "AUTO")
if(TLS_KEYWORD)
set(IGRAPH_ENABLE_TLS ON)
else()
set(IGRAPH_ENABLE_TLS OFF)
endif()
endif()
if(IGRAPH_ENABLE_TLS)
if(NOT TLS_KEYWORD)
message(FATAL_ERROR "Thread-local storage not supported on this compiler")
endif()
# TODO: we should probably set this only if we are building igraph with
# internal-everything
set(IGRAPH_THREAD_SAFE YES)
else()
set(TLS_KEYWORD "")
set(IGRAPH_THREAD_SAFE NO)
endif()
@@ -0,0 +1,43 @@
include(CheckCXXSourceCompiles)
include(CheckTypeSize)
cmake_push_check_state(RESET)
# Check whether the compiler supports the _umul128() intrinsic
check_cxx_source_compiles("
#include <intrin.h>
int main(void) {
unsigned long long a = 0, b = 0;
unsigned long long c;
volatile unsigned long long d;
d = _umul128(a, b, &c);
return 0;
}
"
HAVE__UMUL128
)
# Check whether the compiler supports the __umulh() intrinsic
check_cxx_source_compiles("
#include <intrin.h>
int main(void) {
unsigned long long a = 0, b = 0;
volatile unsigned long long c;
c = __umulh(a, b);
return 0;
}
"
HAVE___UMULH
)
# Check whether the compiler has __uint128_t
check_type_size("__uint128_t" UINT128 LANGUAGE CXX)
if(UINT128 EQUAL 16)
set(HAVE___UINT128_T ON)
else()
set(HAVE___UINT128_T OFF)
endif()
cmake_pop_check_state()
@@ -0,0 +1,90 @@
include(GetGitRevisionDescription)
# At this point, igraph is either the main CMake project or a subproject of
# another project. CMAKE_SOURCE_DIR would point to the root of the main
# project if we are a subproject so we cannot use that; we need to use
# CMAKE_CURRENT_SOURCE_DIR to get the directory containing the CMakeLists.txt
# file that version.cmake was included from, which is the top-level
# CMakeLists.txt file of igraph itself
set(VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/IGRAPH_VERSION")
set(NEXT_VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/NEXT_VERSION")
if(EXISTS "${VERSION_FILE}")
file(READ "${VERSION_FILE}" PACKAGE_VERSION)
string(STRIP "${PACKAGE_VERSION}" PACKAGE_VERSION)
message(STATUS "Version number: ${PACKAGE_VERSION}")
else()
find_package(Git QUIET)
if(Git_FOUND)
git_describe(PACKAGE_VERSION)
else()
set(PACKAGE_VERSION "NOTFOUND")
endif()
if(PACKAGE_VERSION)
if(EXISTS "${NEXT_VERSION_FILE}")
file(READ "${NEXT_VERSION_FILE}" PACKAGE_VERSION)
string(STRIP "${PACKAGE_VERSION}" PACKAGE_VERSION)
get_git_head_revision(GIT_REFSPEC GIT_COMMIT_HASH)
string(SUBSTRING "${GIT_COMMIT_HASH}" 0 8 GIT_COMMIT_HASH_SHORT)
string(APPEND PACKAGE_VERSION "-dev+${GIT_COMMIT_HASH_SHORT}")
endif()
message(STATUS "Version number from Git: ${PACKAGE_VERSION}")
elseif(EXISTS "${NEXT_VERSION_FILE}")
file(READ "${NEXT_VERSION_FILE}" PACKAGE_VERSION)
string(STRIP "${PACKAGE_VERSION}" PACKAGE_VERSION)
string(APPEND PACKAGE_VERSION "-dev")
message(STATUS "Version number: ${PACKAGE_VERSION}")
else()
message(STATUS "Cannot find out the version number of this package; IGRAPH_VERSION is missing.")
message(STATUS "")
message(STATUS "The official igraph tarballs should contain this file, therefore you are")
message(STATUS "most likely trying to compile a development version yourself. The development")
message(STATUS "versions need Git to be able to determine the version number of igraph.")
message(STATUS "")
if(Git_FOUND)
message(STATUS "It seems like you do have Git but it failed to determine the package version number.")
message(STATUS "")
message(STATUS "Git was found at: ${GIT_EXECUTABLE}")
message(STATUS "The version number detection failed with: ${PACKAGE_VERSION}")
message(STATUS "")
message(STATUS "Most frequently this is caused by a shallow Git checkout that contains no tags in the history.")
else()
message(STATUS "Please install Git, make sure it is in your path, and then try again.")
endif()
message(STATUS "")
message(FATAL_ERROR "Configuration failed.")
endif()
endif()
string(REGEX MATCH "^[^-]+" PACKAGE_VERSION_BASE "${PACKAGE_VERSION}")
string(
REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9+])" "\\1;\\2;\\3"
PACKAGE_VERSION_PARTS "${PACKAGE_VERSION_BASE}"
)
list(GET PACKAGE_VERSION_PARTS 0 PACKAGE_VERSION_MAJOR)
list(GET PACKAGE_VERSION_PARTS 1 PACKAGE_VERSION_MINOR)
list(GET PACKAGE_VERSION_PARTS 2 PACKAGE_VERSION_PATCH)
if(PACKAGE_VERSION MATCHES "^[^-]+-")
string(
REGEX REPLACE "^[^-]+-([^+]*)" "\\1" PACKAGE_VERSION_PRERELEASE "${PACKAGE_VERSION}"
)
else()
set(PACKAGE_VERSION_PRERELEASE "cmake-experimental")
endif()
# Add a target that we can use to generate an IGRAPH_VERSION file in the build
# folder, for the sake of creating a tarball. This is needed only if igraph is
# the main project
if(NOT PROJECT_NAME)
add_custom_target(
versionfile
BYPRODUCTS "${CMAKE_BINARY_DIR}/IGRAPH_VERSION"
COMMAND "${CMAKE_COMMAND}"
-DIGRAPH_VERSION="${PACKAGE_VERSION}"
-DVERSION_FILE_PATH="${CMAKE_BINARY_DIR}/IGRAPH_VERSION"
-P "${CMAKE_SOURCE_DIR}/etc/cmake/create_igraph_version_file.cmake"
COMMENT "Generating IGRAPH_VERSION file in build folder"
)
endif()