3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-22 08:35:31 +00:00

[CMake] Move CMake files into their intended location so the

`contrib/cmake/bootstrap.py` script no longer needs to be executed.

The previous location of the CMake files was a compromise proposed
by @agurfinkel in #461. While this has served us well (allowing progress
to be made) over time limitations of this approach have appeared.

The main problem is that doing many git operations (e.g. pull, rebase)
means the CMake files don't get updated unless the user remembers to
run the script. This can lead to broken and confusing build system
behaviour.

This commit only does the file moving and necessary changes to
`.gitignore`. Other changes will be done in subsequent commits.
This commit is contained in:
Dan Liew 2017-06-12 10:21:50 +01:00
parent f0fa439c48
commit 4b517b96df
97 changed files with 0 additions and 11 deletions

30
cmake/Z3Config.cmake.in Normal file
View file

@ -0,0 +1,30 @@
################################################################################
# @AUTO_GEN_MSG@
#
# This file is intended to be consumed by clients who wish to use Z3 from CMake.
# It can be use by doing `find_package(Z3 config)` from within a
# `CMakeLists.txt` file. If CMake doesn't find this package automatically you
# can give it a hint by passing `-DZ3_DIR=<path>` to the CMake invocation where
# `<path>` is the path to the directory containing this file.
#
# This file was built for the @CONFIG_FILE_TYPE@.
################################################################################
# Exported targets
include("${CMAKE_CURRENT_LIST_DIR}/Z3Targets.cmake")
@PACKAGE_INIT@
# Version information
set(Z3_VERSION_MAJOR @Z3_VERSION_MAJOR@)
set(Z3_VERSION_MINOR @Z3_VERSION_MINOR@)
set(Z3_VERSION_PATCH @Z3_VERSION_PATCH@)
set(Z3_VERSION_TWEAK @Z3_VERSION_TWEAK@)
set(Z3_VERSION_STRING "${Z3_VERSION_MAJOR}.${Z3_VERSION_MINOR}.${Z3_VERSION_PATCH}.${Z3_VERSION_TWEAK}")
# NOTE: We can't use `set_and_check()` here because this a list of paths.
# List of include directories
set(Z3_C_INCLUDE_DIRS @PACKAGE_Z3_FIRST_PACKAGE_INCLUDE_DIR@ @PACKAGE_Z3_SECOND_PACKAGE_INCLUDE_DIR@)
set(Z3_CXX_INCLUDE_DIRS @PACKAGE_Z3_CXX_PACKAGE_INCLUDE_DIR@ ${Z3_C_INCLUDE_DIRS})
# List of libraries to link against
set(Z3_LIBRARIES "z3::libz3")

View file

@ -0,0 +1,24 @@
if(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
message(FATAL_ERROR "Cannot find install manifest: "
"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
endif()
file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
foreach(file ${files})
set(_full_file_path "$ENV{DESTDIR}${file}")
message(STATUS "Uninstalling ${_full_file_path}")
if(IS_SYMLINK "${_full_file_path}" OR EXISTS "${_full_file_path}")
# We could use ``file(REMOVE ...)`` here but then we wouldn't
# know if the removal failed.
execute_process(COMMAND
"@CMAKE_COMMAND@" "-E" "remove" "${_full_file_path}"
RESULT_VARIABLE rm_retval
)
if(NOT "${rm_retval}" STREQUAL 0)
message(FATAL_ERROR "Problem when removing \"${_full_file_path}\"")
endif()
else()
message(STATUS "File \"${_full_file_path}\" does not exist.")
endif()
endforeach()

52
cmake/compiler_lto.cmake Normal file
View file

@ -0,0 +1,52 @@
option(LINK_TIME_OPTIMIZATION "Use link time optimiziation" OFF)
if (LINK_TIME_OPTIMIZATION)
message(STATUS "LTO enabled")
set(build_types_with_lto "RELEASE" "RELWITHDEBINFO")
if (DEFINED CMAKE_CONFIGURATION_TYPES)
# Multi configuration generator
message(STATUS "Note LTO is only enabled for the following configurations: ${build_types_with_lto}")
else()
# Single configuration generator
string(TOUPPER "${CMAKE_BUILD_TYPE}" _build_type_upper)
list(FIND build_types_with_lto "${_build_type_upper}" _index)
if ("${_index}" EQUAL -1)
message(FATAL_ERROR "Configuration ${CMAKE_BUILD_TYPE} does not support LTO."
"You should set LINK_TIME_OPTIMIZATION to OFF.")
endif()
endif()
set(_lto_compiler_flag "")
set(_lto_linker_flag "")
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR
("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU"))
set(_lto_compiler_flag "-flto")
set(_lto_linker_flag "-flto")
# FIXME: Remove "x.." when CMP0054 is set to NEW
elseif ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
set(_lto_compiler_flag "/GL")
set(_lto_linker_flag "/LTCG")
else()
message(FATAL_ERROR "Can't enable LTO for compiler \"${CMAKE_CXX_COMPILER_ID}\"."
"You should set LINK_TIME_OPTIMIZATION to OFF.")
endif()
CHECK_CXX_COMPILER_FLAG("${_lto_compiler_flag}" HAS_LTO)
if (NOT HAS_LTO)
message(FATAL_ERROR "Compiler does not support LTO")
endif()
foreach (_config ${build_types_with_lto})
# Set flags compiler and linker flags globally rather than using
# `Z3_COMPONENT_CXX_FLAGS` and `Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS`
# respectively. We need per configuration compiler and linker flags. The
# `LINK_FLAGS` property (which we populate with
# `Z3_DEPENDENT_EXTRA_CXX_LINK_FLAGS`) doesn't seem to support generator
# expressions so we can't do `$<$<CONFIG:Release>:${_lto_linker_flag}>`.
set(CMAKE_CXX_FLAGS_${_config} "${CMAKE_CXX_FLAGS_${_config}} ${_lto_compiler_flag}")
set(CMAKE_EXE_LINKER_FLAGS_${_config} "${CMAKE_EXE_LINKER_FLAGS_${_config}} ${_lto_linker_flag}")
set(CMAKE_SHARED_LINKER_FLAGS_${_config} "${CMAKE_SHARED_LINKER_FLAGS_${_config}} ${_lto_linker_flag}")
set(CMAKE_STATIC_LINKER_FLAGS_${_config} "${CMAKE_STATIC_LINKER_FLAGS_${_config}} ${_lto_linker_flag}")
endforeach()
else()
message(STATUS "LTO disabled")
endif()

View file

@ -0,0 +1,54 @@
set(GCC_AND_CLANG_WARNINGS
"-Wall"
)
set(GCC_ONLY_WARNINGS "")
set(CLANG_ONLY_WARNINGS "")
set(MSVC_WARNINGS "/W3")
set(WARNING_FLAGS_TO_CHECK "")
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
list(APPEND WARNING_FLAGS_TO_CHECK ${GCC_AND_CLANG_WARNINGS})
list(APPEND WARNING_FLAGS_TO_CHECK ${GCC_ONLY_WARNINGS})
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
list(APPEND WARNING_FLAGS_TO_CHECK ${GCC_AND_CLANG_WARNINGS})
list(APPEND WARNING_FLAGS_TO_CHECK ${CLANG_ONLY_WARNINGS})
# FIXME: Remove "x.." when CMP0054 is set to NEW
elseif ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
list(APPEND WARNING_FLAGS_TO_CHECK ${MSVC_WARNINGS})
# CMake's default flags include /W3 already so remove them if
# they already exist.
if ("${CMAKE_CXX_FLAGS}" MATCHES "/W3")
string(REPLACE "/W3" "" _cmake_cxx_flags_remove_w3 "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${_cmake_cxx_flags_remove_w3}" CACHE STRING "" FORCE)
endif()
else()
message(AUTHOR_WARNING "Unknown compiler")
endif()
# Loop through flags and use the ones which the compiler supports
foreach (flag ${WARNING_FLAGS_TO_CHECK})
z3_add_cxx_flag("${flag}")
endforeach()
option(WARNINGS_AS_ERRORS "Treat compiler warnings as errors" OFF)
if (WARNINGS_AS_ERRORS)
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU"))
list(APPEND Z3_COMPONENT_CXX_FLAGS "-Werror")
# FIXME: Remove "x.." when CMP0054 is set to NEW
elseif ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
list(APPEND Z3_COMPONENT_CXX_FLAGS "/WX")
else()
message(AUTHOR_WARNING "Unknown compiler")
endif()
message(STATUS "Treating compiler warnings as errors")
else()
message(STATUS "Not treating compiler warnings as errors")
# FIXME: Remove "x.." when CMP0054 is set to NEW
if ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
# Warnings as errors is off by default for MSVC so setting this
# is not necessary but this duplicates the behaviour of the old
# build system.
list(APPEND Z3_COMPONENT_CXX_FLAGS "/WX-")
endif()
endif()

View file

@ -0,0 +1,14 @@
# This file overrides the default compiler flags for CMake's built-in
# configurations (CMAKE_BUILD_TYPE). Most compiler flags should not be set here.
# The main purpose is to have very fine grained control of the compiler flags.
# We only override the defaults for Clang and GCC right now.
# CMake's MSVC logic is complicated so for now it's better to just inherit CMake's defaults.
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU"))
# Taken from Modules/Compiler/GNU.cmake
set(CMAKE_CXX_FLAGS_INIT "")
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-g -O0")
set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "-O3 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O2 -g -DNDEBUG")
endif()

173
cmake/git_utils.cmake Normal file
View file

@ -0,0 +1,173 @@
# add_git_dir_dependency(GIT_DIR SUCCESS_VAR)
#
# Adds a configure time dependency on the git directory such that if the HEAD
# of the git directory changes CMake will be forced to re-run. This useful
# for fetching the current git hash and including it in the build.
#
# `GIT_DIR` is the path to the git directory (i.e. the `.git` directory)
# `SUCCESS_VAR` is the name of the variable to set. It will be set to TRUE
# if the dependency was successfully added and FALSE otherwise.
function(add_git_dir_dependency GIT_DIR SUCCESS_VAR)
if (NOT "${ARGC}" EQUAL 2)
message(FATAL_ERROR "Invalid number (${ARGC}) of arguments")
endif()
if (NOT IS_ABSOLUTE "${GIT_DIR}")
message(FATAL_ERROR "GIT_DIR (\"${GIT_DIR}\") is not an absolute path")
endif()
if (NOT IS_DIRECTORY "${GIT_DIR}")
message(FATAL_ERROR "GIT_DIR (\"${GIT_DIR}\") is not a directory")
endif()
set(GIT_HEAD_FILE "${GIT_DIR}/HEAD")
if (NOT EXISTS "${GIT_HEAD_FILE}")
message(AUTHOR_WARNING "Git head file \"${GIT_HEAD_FILE}\" cannot be found")
set(${SUCCESS_VAR} FALSE PARENT_SCOPE)
return()
endif()
# List of files in the git tree that CMake configuration should depend on
set(GIT_FILE_DEPS "${GIT_HEAD_FILE}")
# Examine the HEAD and workout what additional dependencies there are.
file(READ "${GIT_HEAD_FILE}" GIT_HEAD_DATA LIMIT 128)
string(STRIP "${GIT_HEAD_DATA}" GIT_HEAD_DATA_STRIPPED)
if ("${GIT_HEAD_DATA_STRIPPED}" MATCHES "^ref:[ ]*(.+)$")
# HEAD points at a reference.
set(GIT_REF "${CMAKE_MATCH_1}")
if (EXISTS "${GIT_DIR}/${GIT_REF}")
# Unpacked reference. The file contains the commit hash
# so add a dependency on this file so that if we stay on this
# reference (i.e. branch) but change commit CMake will be forced
# to reconfigure.
list(APPEND GIT_FILE_DEPS "${GIT_DIR}/${GIT_REF}")
elseif(EXISTS "${GIT_DIR}/packed-refs")
# The ref must be packed (see `man git-pack-refs`).
list(APPEND GIT_FILE_DEPS "${GIT_DIR}/packed-refs")
else()
# Fail
message(AUTHOR_WARNING "Unhandled git reference")
set(${SUCCESS_VAR} FALSE PARENT_SCOPE)
return()
endif()
else()
# Detached HEAD.
# No other dependencies needed
endif()
# FIXME:
# This is the directory we will copy (via `configure_file()`) git files
# into. This is a hack. It would be better to use the
# `CMAKE_CONFIGURE_DEPENDS` directory property but that feature is not
# available in CMake 2.8.12. So we use `configure_file()` to effectively
# do the same thing. When the source file to `configure_file()` changes
# it will trigger a re-run of CMake.
set(GIT_CMAKE_FILES_DIR "${CMAKE_CURRENT_BINARY_DIR}/git_cmake_files")
file(MAKE_DIRECTORY "${GIT_CMAKE_FILES_DIR}")
foreach (git_dependency ${GIT_FILE_DEPS})
message(STATUS "Adding git dependency \"${git_dependency}\"")
configure_file(
"${git_dependency}"
"${GIT_CMAKE_FILES_DIR}"
COPYONLY
)
endforeach()
set(${SUCCESS_VAR} TRUE PARENT_SCOPE)
endfunction()
# get_git_head_hash(GIT_DIR OUTPUT_VAR)
#
# Retrieve the current commit hash for a git working directory where `GIT_DIR`
# is the `.git` directory in the root of the git working directory.
#
# `OUTPUT_VAR` should be the name of the variable to put the result in. If this
# function fails then either a fatal error will be raised or `OUTPUT_VAR` will
# contain a string with the suffix `NOTFOUND` which can be used in CMake `if()`
# commands.
function(get_git_head_hash GIT_DIR OUTPUT_VAR)
if (NOT "${ARGC}" EQUAL 2)
message(FATAL_ERROR "Invalid number of arguments")
endif()
if (NOT IS_DIRECTORY "${GIT_DIR}")
message(FATAL_ERROR "\"${GIT_DIR}\" is not a directory")
endif()
if (NOT IS_ABSOLUTE "${GIT_DIR}")
message(FATAL_ERROR \""${GIT_DIR}\" is not an absolute path")
endif()
find_package(Git)
if (NOT Git_FOUND)
set(${OUTPUT_VAR} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
get_filename_component(GIT_WORKING_DIR "${GIT_DIR}" DIRECTORY)
execute_process(
COMMAND
"${GIT_EXECUTABLE}"
"rev-parse"
"-q" # Quiet
"HEAD"
WORKING_DIRECTORY
"${GIT_WORKING_DIR}"
RESULT_VARIABLE
GIT_EXIT_CODE
OUTPUT_VARIABLE
Z3_GIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (NOT "${GIT_EXIT_CODE}" EQUAL 0)
message(WARNING "Failed to execute git")
set(${OUTPUT_VAR} NOTFOUND PARENT_SCOPE)
return()
endif()
set(${OUTPUT_VAR} "${Z3_GIT_HASH}" PARENT_SCOPE)
endfunction()
# get_git_head_describe(GIT_DIR OUTPUT_VAR)
#
# Retrieve the output of `git describe` for a git working directory where
# `GIT_DIR` is the `.git` directory in the root of the git working directory.
#
# `OUTPUT_VAR` should be the name of the variable to put the result in. If this
# function fails then either a fatal error will be raised or `OUTPUT_VAR` will
# contain a string with the suffix `NOTFOUND` which can be used in CMake `if()`
# commands.
function(get_git_head_describe GIT_DIR OUTPUT_VAR)
if (NOT "${ARGC}" EQUAL 2)
message(FATAL_ERROR "Invalid number of arguments")
endif()
if (NOT IS_DIRECTORY "${GIT_DIR}")
message(FATAL_ERROR "\"${GIT_DIR}\" is not a directory")
endif()
if (NOT IS_ABSOLUTE "${GIT_DIR}")
message(FATAL_ERROR \""${GIT_DIR}\" is not an absolute path")
endif()
find_package(Git)
if (NOT Git_FOUND)
set(${OUTPUT_VAR} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
get_filename_component(GIT_WORKING_DIR "${GIT_DIR}" DIRECTORY)
execute_process(
COMMAND
"${GIT_EXECUTABLE}"
"describe"
"--long"
WORKING_DIRECTORY
"${GIT_WORKING_DIR}"
RESULT_VARIABLE
GIT_EXIT_CODE
OUTPUT_VARIABLE
Z3_GIT_DESCRIPTION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (NOT "${GIT_EXIT_CODE}" EQUAL 0)
message(WARNING "Failed to execute git")
set(${OUTPUT_VAR} NOTFOUND PARENT_SCOPE)
return()
endif()
set(${OUTPUT_VAR} "${Z3_GIT_DESCRIPTION}" PARENT_SCOPE)
endfunction()

View file

@ -0,0 +1,53 @@
# Tries to find a working .NET tool chain
#
# Once complete this will define
# DOTNET_TOOLCHAIN_FOUND : BOOL : System has a .NET toolchain
# DOTNET_CSC_EXECUTABLE - STRING : Path to C# compiler
# DOTNET_GACUTIL_EXECUTABLE - STRING : Path to gacutil
# DOTNET_TOOLCHAIN_IS_MONO : BOOL : True if detected .NET toolchain is Mono
# DOTNET_TOOLCHAIN_IS_WINDOWS : BOOL : True if detected .NET toolchain is native Windows
include(FindPackageHandleStandardArgs)
find_program(
DOTNET_CSC_EXECUTABLE
NAMES "csc.exe" "mcs" "dmcs"
)
message(STATUS "DOTNET_CSC_EXECUTABLE: \"${DOTNET_CSC_EXECUTABLE}\"")
find_program(
DOTNET_GACUTIL_EXECUTABLE
NAMES "gacutil.exe" "gacutil"
)
message(STATUS "DOTNET_GACUTIL_EXECUTABLE: \"${DOTNET_GACUTIL_EXECUTABLE}\"")
# Try to determine the tool chain vendor
set(DOTNET_DETERMINED_VENDOR FALSE)
if (DOTNET_CSC_EXECUTABLE)
execute_process(COMMAND "${DOTNET_CSC_EXECUTABLE}" "/help"
RESULT_VARIABLE CSC_EXIT_CODE
OUTPUT_VARIABLE CSC_STD_OUT
)
if (${CSC_EXIT_CODE} EQUAL 0)
if ("${CSC_STD_OUT}" MATCHES "^Mono[ ]+C#")
set(DOTNET_DETERMINED_VENDOR TRUE)
set(DOTNET_TOOLCHAIN_IS_MONO TRUE)
set(DOTNET_TOOLCHAIN_IS_WINDOWS FALSE)
message(STATUS ".NET toolchain is Mono")
elseif ("${CSC_STD_OUT}" MATCHES "^Microsoft.+Visual[ ]+C#")
set(DOTNET_DETERMINED_VENDOR TRUE)
set(DOTNET_TOOLCHAIN_IS_MONO FALSE)
set(DOTNET_TOOLCHAIN_IS_WINDOWS TRUE)
message(STATUS ".NET toolchain is Windows native")
else()
message(STATUS ".NET toolchain is unknown")
endif()
endif()
endif()
# TODO: Check C# compiler works
find_package_handle_standard_args(DotNetToolChain DEFAULT_MSG
DOTNET_CSC_EXECUTABLE
DOTNET_GACUTIL_EXECUTABLE
DOTNET_DETERMINED_VENDOR
)

View file

@ -0,0 +1,64 @@
# Tries to find an install of the GNU multiple precision library
#
# Once done this will define
# GMP_FOUND - BOOL: System has the GMP library installed
# GMP_INCLUDE_DIRS - LIST:The GMP include directories
# GMP_C_LIBRARIES - LIST:The libraries needed to use GMP via it's C interface
# GMP_CXX_LIBRARIES - LIST:The libraries needed to use GMP via it's C++ interface
include(FindPackageHandleStandardArgs)
# Try to find libraries
find_library(GMP_C_LIBRARIES
NAMES gmp
DOC "GMP C libraries"
)
if (GMP_C_LIBRARIES)
message(STATUS "Found GMP C library: \"${GMP_C_LIBRARIES}\"")
else()
message(STATUS "Could not find GMP C library")
endif()
find_library(GMP_CXX_LIBRARIES
NAMES gmpxx
DOC "GMP C++ libraries"
)
if (GMP_CXX_LIBRARIES)
message(STATUS "Found GMP C++ library: \"${GMP_CXX_LIBRARIES}\"")
else()
message(STATUS "Could not find GMP C++ library")
endif()
# Try to find headers
find_path(GMP_C_INCLUDES
NAMES gmp.h
DOC "GMP C header"
)
if (GMP_C_INCLUDES)
message(STATUS "Found GMP C include path: \"${GMP_C_INCLUDES}\"")
else()
message(STATUS "Could not find GMP C include path")
endif()
find_path(GMP_CXX_INCLUDES
NAMES gmpxx.h
DOC "GMP C++ header"
)
if (GMP_CXX_INCLUDES)
message(STATUS "Found GMP C++ include path: \"${GMP_CXX_INCLUDES}\"")
else()
message(STATUS "Could not find GMP C++ include path")
endif()
if (GMP_C_LIBRARIES AND GMP_CXX_LIBRARIES AND GMP_C_INCLUDES AND GMP_CXX_INCLUDES)
set(GMP_INCLUDE_DIRS "${GMP_C_INCLUDES}" "${GMP_CXX_INCLUDES}")
list(REMOVE_DUPLICATES GMP_INCLUDE_DIRS)
message(STATUS "Found GMP")
else()
message(STATUS "Could not find GMP")
endif()
# TODO: We should check we can link some simple code against libgmp and libgmpxx
# Handle QUIET and REQUIRED and check the necessary variables were set and if so
# set ``GMP_FOUND``
find_package_handle_standard_args(GMP DEFAULT_MSG GMP_INCLUDE_DIRS GMP_C_LIBRARIES GMP_CXX_LIBRARIES)

View file

@ -0,0 +1,194 @@
# This file ether sets or notes various compiler and linker flags for MSVC that
# were defined by the old python/Makefile based build system but
# don't obviously belong in the other sections in the CMake build system.
################################################################################
# Compiler definitions
################################################################################
# FIXME: All the commented out defines should be removed once
# we are confident it is correct to not set them.
set(Z3_MSVC_LEGACY_DEFINES
# Don't set `_DEBUG`. The old build sytem sets this but this
# is wrong. MSVC will set this depending on which runtime is being used.
# See https://msdn.microsoft.com/en-us/library/b0084kay.aspx
# _DEBUG
# The old build system only set `UNICODE` and `_UNICODE` for x86_64 release.
# That seems completly wrong so set it for all configurations.
# According to https://blogs.msdn.microsoft.com/oldnewthing/20040212-00/?p=40643/
# `UNICODE` affects Windows headers and `_UNICODE` affects C runtime header files.
# There is some discussion of this define at https://msdn.microsoft.com/en-us/library/dybsewaf.aspx
UNICODE
_UNICODE
)
if ("${TARGET_ARCHITECTURE}" STREQUAL "x86_64")
list(APPEND Z3_MSVC_LEGACY_DEFINES ""
# Don't set `_LIB`. The old build system sets this for x86_64 release
# build. This flag doesn't seem to be documented but a stackoverflow
# post hints that this is usually set when building a static library.
# See http://stackoverflow.com/questions/35034683/how-to-tell-if-current-project-is-dll-or-static-lib
# This seems wrong give that the old build system set this regardless
# whether or not libz3 was static or shared so its probably best
# to not set for now.
#$<$<CONFIG:Release>:_LIB>
#$<$<CONFIG:RelWithDebInfo>:_LIB>
# Don't set `_CONSOLE`. The old build system sets for all configurations
# except x86_64 release. It seems ( https://codeyarns.com/2010/12/02/visual-c-windows-and-console-subsystems/ )
# that `_CONSOLE` used to be defined by older Visual C++ environments.
# Setting this undocumented option seems like a bad idea so let's not do it.
#$<$<CONFIG:Debug:_CONSOLE>
#$<$<CONFIG:MinSizeRel:_CONSOLE>
# Don't set `ASYNC_COMMANDS`. The old build system sets this for x86_64
# release but this macro does not appear to be used anywhere and is not
# documented so don't set it for now.
#$<$<CONFIG:Release>:ASYNC_COMMANDS>
#$<$<CONFIG:RelWithDebInfo>:ASYNC_COMMANDS>
)
else()
list(APPEND Z3_MSVC_LEGACY_DEFINES ""
# Don't set `_CONSOLE`. See reasoning above.
#_CONSOLE
)
endif()
# Note we don't set WIN32 or _WINDOWS because
# CMake provides that for us. As a sanity check make sure the option
# is present.
if (NOT "${CMAKE_CXX_FLAGS}" MATCHES "/D[ ]*WIN32")
message(FATAL_ERROR "\"/D WIN32\" is missing")
endif()
if (NOT "${CMAKE_CXX_FLAGS}" MATCHES "/D[ ]*_WINDOWS")
message(FATAL_ERROR "\"/D _WINDOWS\" is missing")
endif()
list(APPEND Z3_COMPONENT_CXX_DEFINES ${Z3_MSVC_LEGACY_DEFINES})
################################################################################
# Compiler flags
################################################################################
# By default in MSVC this is on but the old build system set this explicitly so
# for completeness set it too.
# See https://msdn.microsoft.com/en-us/library/dh8che7s.aspx
z3_add_cxx_flag("/Zc:wchar_t" REQUIRED)
# By default in MSVC this on but the old build system set this explicitly so
# for completeness set it too.
z3_add_cxx_flag("/Zc:forScope" REQUIRED)
# FIXME: We might want to move this out somewhere else if we decide
# we want to set `-fno-omit-frame-pointer` for gcc/clang.
# No omit frame pointer
set(NO_OMIT_FRAME_POINTER_MSVC_FLAG "/Oy-")
CHECK_CXX_COMPILER_FLAG(${NO_OMIT_FRAME_POINTER_MSVC_FLAG} HAS_MSVC_NO_OMIT_FRAME_POINTER)
if (NOT HAS_MSVC_NO_OMIT_FRAME_POINTER)
message(FATAL_ERROR "${NO_OMIT_FRAME_POINTER_MSVC_FLAG} flag not supported")
endif()
# FIXME: This doesn't make a huge amount of sense but the old
# build system kept the frame pointer for all configurations
# except x86_64 release (I don't know why the frame pointer
# is kept for i686 release).
if ("${TARGET_ARCHITECTURE}" STREQUAL "x86_64")
list(APPEND Z3_COMPONENT_CXX_FLAGS
$<$<CONFIG:Debug>:${NO_OMIT_FRAME_POINTER_MSVC_FLAG}>
$<$<CONFIG:MinSizeRel>:${NO_OMIT_FRAME_POINTER_MSVC_FLAG}>
)
else()
list(APPEND Z3_COMPONENT_CXX_FLAGS ${NO_OMIT_FRAME_POINTER_MSVC_FLAG})
endif()
if (("${TARGET_ARCHITECTURE}" STREQUAL "x86_64") OR ("${TARGET_ARCHITECTURE}" STREQUAL "i686"))
# Use __cdecl calling convention. Apparently this is MSVC's default
# but the old build system set it so for completeness set it too.
# See https://msdn.microsoft.com/en-us/library/46t77ak2.aspx
z3_add_cxx_flag("/Gd" REQUIRED)
endif()
# FIXME: The old build system explicitly disables code analysis.
# I don't know why. Duplicate this behaviour for now.
# See https://msdn.microsoft.com/en-us/library/ms173498.aspx
z3_add_cxx_flag("/analyze-" REQUIRED)
################################################################################
# Linker flags
################################################################################
# By default CMake enables incremental linking for Debug and RelWithDebInfo
# builds. The old build sytem disables it for all builds so try to do the same
# by changing all configurations if necessary
string(TOUPPER "${available_build_types}" _build_types_as_upper)
foreach (_build_type ${_build_types_as_upper})
foreach (t EXE SHARED STATIC)
set(_replacement "/INCREMENTAL:NO")
# Remove any existing incremental flags
string(REGEX REPLACE
"/INCREMENTAL:YES"
"${_replacement}"
_replaced_linker_flags
"${CMAKE_${t}_LINKER_FLAGS_${_build_type}}")
string(REGEX REPLACE
"(/INCREMENTAL$)|(/INCREMENTAL )"
"${_replacement} "
_replaced_linker_flags
"${_replaced_linker_flags}")
if (NOT "${_replaced_linker_flags}" MATCHES "${_replacement}")
# Flag not present. Add it
string(APPEND _replaced_linker_flags " ${_replacement}")
endif()
set(CMAKE_${t}_LINKER_FLAGS_${_build_type} "${_replaced_linker_flags}")
endforeach()
endforeach()
# The original build system passes `/STACK:` to the linker.
# This size comes from the original build system.
# FIXME: What is the rationale behind this?
set(STACK_SIZE_MSVC_LINKER 8388608)
# MSVC documentation (https://msdn.microsoft.com/en-us/library/35yc2tc3.aspx)
# says this only matters for executables which is why this is not being
# set for CMAKE_SHARED_LINKER_FLAGS or CMAKE_STATIC_LINKER_FLAGS.
string(APPEND CMAKE_EXE_LINKER_FLAGS " /STACK:${STACK_SIZE_MSVC_LINKER}")
# The original build system passes `/SUBSYSTEM:<X>` to the linker where `<X>`
# depends on what is being linked. Where `<X>` is `CONSOLE` for executables
# and `WINDOWS` for shard libraries.
# We don't need to pass `/SUBSYSTEM:CONSOLE` because CMake will do this for
# us when building executables because we don't pass the `WIN32` argument to
# `add_executable()`.
# FIXME: We probably don't need this. https://msdn.microsoft.com/en-us/library/fcc1zstk.aspx
# suggests that `/SUBSYSTEM:` only matters for executables.
string(APPEND CMAKE_SHARED_LINKER_FLAGS " /SUBSYSTEM:WINDOWS")
# FIXME: The following linker flags are weird. They are set in all configurations
# in the old build system except release x86_64. We try to emulate this here but
# this is likely the wrong thing to do.
foreach (_build_type ${_build_types_as_upper})
if ("${TARGET_ARCHITECTURE}" STREQUAL "x86_64" AND
("${_build_type}" STREQUAL "RELEASE" OR
"${_build_type}" STREQUAL "RELWITHDEBINFO")
)
message(AUTHOR_WARNING "Skipping legacy linker MSVC options for x86_64 ${_build_type}")
else()
# Linker optimizations.
# See https://msdn.microsoft.com/en-us/library/bxwfs976.aspx
string(APPEND CMAKE_EXE_LINKER_FLAGS_${_build_type} " /OPT:REF /OPT:ICF")
string(APPEND CMAKE_SHARED_LINKER_FLAGS_${_build_type} " /OPT:REF /OPT:ICF")
# FIXME: This is not necessary. This is MSVC's default.
# See https://msdn.microsoft.com/en-us/library/b1kw34cb.aspx
string(APPEND CMAKE_EXE_LINKER_FLAGS_${_build_type} " /TLBID:1")
string(APPEND CMAKE_SHARED_LINKER_FLAGS_${_build_type} " /TLBID:1")
# FIXME: This is not necessary. This is MSVC's default.
# Address space layout randomization
# See https://msdn.microsoft.com/en-us/library/bb384887.aspx
string(APPEND CMAKE_EXE_LINKER_FLAGS_${_build_type} " /DYNAMICBASE")
string(APPEND CMAKE_SHARED_LINKER_FLAGS_${_build_type} " /DYNAMICBASE:NO")
# FIXME: This is not necessary. This is MSVC's default.
# Indicate that the executable is compatible with DEP
# See https://msdn.microsoft.com/en-us/library/ms235442.aspx
string(APPEND CMAKE_EXE_LINKER_FLAGS_${_build_type} " /NXCOMPAT")
endif()
endforeach()

View file

@ -0,0 +1,22 @@
###############################################################################
# Target detection
#
# We abuse the compiler preprocessor to work out what target the compiler is
# building for. The nice thing about this approach is that we'll detect the
# right target even if we are using a cross compiler.
###############################################################################
function(detect_target_architecture OUTPUT_VAR)
try_run(run_result
compile_result
"${CMAKE_BINARY_DIR}"
"${CMAKE_SOURCE_DIR}/cmake/target_arch_detect.cpp"
COMPILE_OUTPUT_VARIABLE compiler_output
)
if (compile_result)
message(FATAL_ERROR "Expected compile to fail")
endif()
string(REGEX MATCH "CMAKE_TARGET_ARCH_([a-zA-Z0-9_]+)" arch "${compiler_output}")
# Strip out prefix
string(REPLACE "CMAKE_TARGET_ARCH_" "" arch "${arch}")
set(${OUTPUT_VAR} "${arch}" PARENT_SCOPE)
endfunction()

View file

@ -0,0 +1,10 @@
// This is used by the CMake build to detect
// what architecture the compiler is targeting.
// TODO: Add more targets here
#if defined(__i386__) || defined(_M_IX86)
#error CMAKE_TARGET_ARCH_i686
#elif defined(__x86_64__) || defined(_M_X64)
#error CMAKE_TARGET_ARCH_x86_64
#else
#error CMAKE_TARGET_ARCH_unknown
#endif

View file

@ -0,0 +1,277 @@
include(CMakeParseArguments)
define_property(GLOBAL PROPERTY Z3_LIBZ3_COMPONENTS
BRIEF_DOCS "List of Z3 components to use in libz3"
FULL_DOCS "List of Z3 components to use in libz3")
function(z3_expand_dependencies output_var)
if (ARGC LESS 2)
message(FATAL_ERROR "Invalid number of arguments")
endif()
# Remaing args should be component names
set(_expanded_deps ${ARGN})
set(_old_number_of_deps 0)
list(LENGTH _expanded_deps _number_of_deps)
while (_number_of_deps GREATER _old_number_of_deps)
set(_old_number_of_deps "${_number_of_deps}")
# Loop over the known dependencies and retrieve their dependencies
set(_old_expanded_deps ${_expanded_deps})
foreach (dependency ${_old_expanded_deps})
get_property(_depdeps GLOBAL PROPERTY Z3_${dependency}_DEPS)
list(APPEND _expanded_deps ${_depdeps})
unset(_depdeps)
endforeach()
list(REMOVE_DUPLICATES _expanded_deps)
list(LENGTH _expanded_deps _number_of_deps)
endwhile()
set(${output_var} ${_expanded_deps} PARENT_SCOPE)
endfunction()
function(z3_add_component_dependencies_to_target target_name)
if (ARGC LESS 2)
message(FATAL_ERROR "Invalid number of arguments")
endif()
if (NOT (TARGET ${target_name}))
message(FATAL_ERROR "Target \"${target_name}\" does not exist")
endif()
# Remaing args should be component names
set(_expanded_deps ${ARGN})
foreach (dependency ${_expanded_deps})
# FIXME: Adding these include paths wouldn't be necessary if the sources
# used include paths rooted in the ``src`` directory.
get_property(_dep_include_dirs GLOBAL PROPERTY Z3_${dependency}_INCLUDES)
foreach (inc_dir ${_dep_include_dirs})
target_include_directories(${target_name} PRIVATE "${inc_dir}")
endforeach()
unset(_dep_include_dirs)
# Ensure this component's dependencies are built before this component.
# This important because we might need the generated header files in
# other components.
add_dependencies(${target_name} ${dependency})
endforeach()
endfunction()
# z3_add_component(component_name
# [NOT_LIBZ3_COMPONENT]
# SOURCES source1 [source2...]
# [COMPONENT_DEPENDENCIES component1 [component2...]]
# [PYG_FILES pygfile1 [pygfile2...]]
# )
#
# Declares a Z3 component (as a CMake "object library") with target name
# ``component_name``.
#
# The option ``NOT_LIBZ3_COMPONENT`` declares that the
# component should not be included in libz3. If this is not specified
# the component will be included in libz3.
#
# The mandatory ``SOURCES`` keyword should be followed by the source files
# (including any files generated at build or configure time) that are should be
# included in the component. It is not necessary to list header files here as
# CMake infers header file dependencies unless that header file is generated at
# build time.
#
# The optional ``COMPONENT_DEPENDENCIES`` keyword should be followed by a list of
# components that ``component_name`` should depend on. The components listed here
# must have already been declared using ``z3_add_component()``. Listing components
# here causes them to be built before ``component_name``. It also currently causes
# the include directories used by the transistive closure of the dependencies
# to be added to the list of include directories used to build ``component_name``.
#
# The optional ``PYG_FILES`` keyword should be followed by a list of one or
# more ``<NAME>.pyg`` files that should used to be generate
# ``<NAME>_params.hpp`` header files used by the ``component_name``.
#
macro(z3_add_component component_name)
CMAKE_PARSE_ARGUMENTS("Z3_MOD" "NOT_LIBZ3_COMPONENT" "" "SOURCES;COMPONENT_DEPENDENCIES;PYG_FILES" ${ARGN})
message(STATUS "Adding component ${component_name}")
# Note: We don't check the sources exist here because
# they might be generated files that don't exist yet.
set(_list_generated_headers "")
foreach (pyg_file ${Z3_MOD_PYG_FILES})
set(_full_pyg_file_path "${CMAKE_CURRENT_SOURCE_DIR}/${pyg_file}")
if (NOT (EXISTS "${_full_pyg_file_path}"))
message(FATAL_ERROR "\"${_full_pyg_file_path}\" does not exist")
endif()
string(REPLACE ".pyg" ".hpp" _output_file "${pyg_file}")
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_output_file}")
message(FATAL_ERROR "\"${CMAKE_CURRENT_SOURCE_DIR}/${_output_file}\" "
${z3_polluted_tree_msg}
)
endif()
set(_full_output_file_path "${CMAKE_CURRENT_BINARY_DIR}/${_output_file}")
message(STATUS "Adding rule to generate \"${_output_file}\"")
add_custom_command(OUTPUT "${_output_file}"
COMMAND "${PYTHON_EXECUTABLE}" "${CMAKE_SOURCE_DIR}/scripts/pyg2hpp.py" "${_full_pyg_file_path}" "${CMAKE_CURRENT_BINARY_DIR}"
MAIN_DEPENDENCY "${_full_pyg_file_path}"
DEPENDS "${CMAKE_SOURCE_DIR}/scripts/pyg2hpp.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
COMMENT "Generating \"${_full_output_file_path}\" from \"${pyg_file}\""
WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
VERBATIM
)
list(APPEND _list_generated_headers "${_full_output_file_path}")
endforeach()
unset(_full_include_dir_path)
unset(_full_output_file_path)
unset(_output_file)
# Using "object" libraries here means we have a convenient
# name to refer to a component in CMake but we don't actually
# create a static/library from them. This allows us to easily
# build a static or dynamic library from the object libraries
# on all platforms. Is this added flexibility worth the linking
# overhead it adds?
add_library(${component_name} OBJECT ${Z3_MOD_SOURCES} ${_list_generated_headers})
unset(_list_generated_headers)
# Add definitions
foreach (define ${Z3_COMPONENT_CXX_DEFINES})
target_compile_definitions(${component_name} PRIVATE ${define})
endforeach()
# Add compiler flags
foreach (flag ${Z3_COMPONENT_CXX_FLAGS})
target_compile_options(${component_name} PRIVATE ${flag})
endforeach()
# It's unfortunate that we have to manage the include directories and dependencies ourselves.
#
# If we weren't building "object" libraries we could use
# ```
# target_include_directories(${component_name} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}")
# target_link_libraries(${component_name} INTERFACE ${Z3_MOD_COMPONENT_DEPENDENCIES})
# ```
# but we can't do that with "object" libraries.
# Record this component's include directories
set_property(GLOBAL PROPERTY Z3_${component_name}_INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}")
set_property(GLOBAL APPEND PROPERTY Z3_${component_name}_INCLUDES "${CMAKE_CURRENT_BINARY_DIR}")
set_property(GLOBAL PROPERTY Z3_${component_name}_DEPS "")
# Record this component's dependencies
foreach (dependency ${Z3_MOD_COMPONENT_DEPENDENCIES})
if (NOT (TARGET ${dependency}))
message(FATAL_ERROR "Component \"${component_name}\" depends on a non existant component \"${dependency}\"")
endif()
set_property(GLOBAL APPEND PROPERTY Z3_${component_name}_DEPS "${dependency}")
endforeach()
# Determine all the components that this component depends on
set(_expanded_deps "")
if (DEFINED Z3_MOD_COMPONENT_DEPENDENCIES)
z3_expand_dependencies(_expanded_deps ${Z3_MOD_COMPONENT_DEPENDENCIES})
z3_add_component_dependencies_to_target(${component_name} ${_expanded_deps})
endif()
#message(STATUS "Component \"${component_name}\" has the following dependencies ${_expanded_deps}")
# For any generated header files for this component
target_include_directories(${component_name} PRIVATE "${CMAKE_CURRENT_BINARY_DIR}")
# So that any generated header files can refer to source files in the component's
# source tree
target_include_directories(${component_name} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}")
# Add any extra include directories
foreach (extra_include ${Z3_COMPONENT_EXTRA_INCLUDE_DIRS})
target_include_directories(${component_name} PRIVATE "${extra_include}")
endforeach()
if (NOT Z3_MOD_NOT_LIBZ3_COMPONENT)
# Add this component to the global list of Z3 components for libz3
set_property(GLOBAL APPEND PROPERTY Z3_LIBZ3_COMPONENTS ${component_name})
endif()
endmacro()
macro(z3_add_install_tactic_rule)
# Arguments should be component names to use
if (ARGC LESS 1)
message(FATAL_ERROR "There should be at least one component")
endif()
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/install_tactic.cpp")
message(FATAL_ERROR "\"${CMAKE_CURRENT_SOURCE_DIR}/install_tactic.cpp\""
${z3_polluted_tree_msg}
)
endif()
z3_expand_dependencies(_expanded_components ${ARGN})
# Get paths to search
set(_search_paths "")
foreach (dependency ${_expanded_components})
get_property(_dep_include_dirs GLOBAL PROPERTY Z3_${dependency}_INCLUDES)
list(APPEND _search_paths ${_dep_include_dirs})
endforeach()
list(APPEND _search_paths "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}")
add_custom_command(OUTPUT "install_tactic.cpp"
COMMAND "${PYTHON_EXECUTABLE}"
"${CMAKE_SOURCE_DIR}/scripts/mk_install_tactic_cpp.py"
"${CMAKE_CURRENT_BINARY_DIR}"
${_search_paths}
DEPENDS "${CMAKE_SOURCE_DIR}/scripts/mk_install_tactic_cpp.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
${_expanded_components}
COMMENT "Generating \"${CMAKE_CURRENT_BINARY_DIR}/install_tactic.cpp\""
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
VERBATIM
)
endmacro()
macro(z3_add_memory_initializer_rule)
# Arguments should be component names to use
if (ARGC LESS 1)
message(FATAL_ERROR "There should be at least one component")
endif()
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/mem_initializer.cpp")
message(FATAL_ERROR "\"${CMAKE_CURRENT_SOURCE_DIR}/mem_initializer.cpp\""
${z3_polluted_tree_msg}
)
endif()
z3_expand_dependencies(_expanded_components ${ARGN})
# Get paths to search
set(_search_paths "")
foreach (dependency ${_expanded_components})
get_property(_dep_include_dirs GLOBAL PROPERTY Z3_${dependency}_INCLUDES)
list(APPEND _search_paths ${_dep_include_dirs})
endforeach()
list(APPEND _search_paths "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}")
add_custom_command(OUTPUT "mem_initializer.cpp"
COMMAND "${PYTHON_EXECUTABLE}"
"${CMAKE_SOURCE_DIR}/scripts/mk_mem_initializer_cpp.py"
"${CMAKE_CURRENT_BINARY_DIR}"
${_search_paths}
DEPENDS "${CMAKE_SOURCE_DIR}/scripts/mk_mem_initializer_cpp.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
${_expanded_components}
COMMENT "Generating \"${CMAKE_CURRENT_BINARY_DIR}/mem_initializer.cpp\""
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
VERBATIM
)
endmacro()
macro(z3_add_gparams_register_modules_rule)
# Arguments should be component names to use
if (ARGC LESS 1)
message(FATAL_ERROR "There should be at least one component")
endif()
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/gparams_register_modules.cpp")
message(FATAL_ERROR "\"${CMAKE_CURRENT_SOURCE_DIR}/gparams_register_modules.cpp\""
${z3_polluted_tree_msg}
)
endif()
z3_expand_dependencies(_expanded_components ${ARGN})
# Get paths to search
set(_search_paths "")
foreach (dependency ${_expanded_components})
get_property(_dep_include_dirs GLOBAL PROPERTY Z3_${dependency}_INCLUDES)
list(APPEND _search_paths ${_dep_include_dirs})
endforeach()
list(APPEND _search_paths "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_BINARY_DIR}")
add_custom_command(OUTPUT "gparams_register_modules.cpp"
COMMAND "${PYTHON_EXECUTABLE}"
"${CMAKE_SOURCE_DIR}/scripts/mk_gparams_register_modules_cpp.py"
"${CMAKE_CURRENT_BINARY_DIR}"
${_search_paths}
DEPENDS "${CMAKE_SOURCE_DIR}/scripts/mk_gparams_register_modules_cpp.py"
${Z3_GENERATED_FILE_EXTRA_DEPENDENCIES}
${_expanded_components}
COMMENT "Generating \"${CMAKE_CURRENT_BINARY_DIR}/gparams_register_modules.cpp\""
${ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG}
VERBATIM
)
endmacro()

View file

@ -0,0 +1,23 @@
include(CheckCXXCompilerFlag)
include(CMakeParseArguments)
function(z3_add_cxx_flag flag)
CMAKE_PARSE_ARGUMENTS(z3_add_flag "REQUIRED" "" "" ${ARGN})
string(REPLACE "-" "_" SANITIZED_FLAG_NAME "${flag}")
string(REPLACE "/" "_" SANITIZED_FLAG_NAME "${SANITIZED_FLAG_NAME}")
string(REPLACE "=" "_" SANITIZED_FLAG_NAME "${SANITIZED_FLAG_NAME}")
string(REPLACE " " "_" SANITIZED_FLAG_NAME "${SANITIZED_FLAG_NAME}")
string(REPLACE ":" "_" SANITIZED_FLAG_NAME "${SANITIZED_FLAG_NAME}")
unset(HAS_${SANITIZED_FLAG_NAME})
CHECK_CXX_COMPILER_FLAG("${flag}" HAS_${SANITIZED_FLAG_NAME})
if (z3_add_flag_REQUIRED AND NOT HAS_${SANITIZED_FLAG_NAME})
message(FATAL_ERROR "The flag \"${flag}\" is required but your C++ compiler doesn't support it")
endif()
if (HAS_${SANITIZED_FLAG_NAME})
message(STATUS "C++ compiler supports ${flag}")
list(APPEND Z3_COMPONENT_CXX_FLAGS "${flag}")
set(Z3_COMPONENT_CXX_FLAGS "${Z3_COMPONENT_CXX_FLAGS}" PARENT_SCOPE)
else()
message(STATUS "C++ compiler does not support ${flag}")
endif()
endfunction()

View file

@ -0,0 +1,17 @@
# The LINK_FLAGS property of a target in CMake is unfortunately a string and
# not a list. This function takes a list of linker flags and iterates through
# them to append them as strings to the ``LINK_FLAGS`` property of
# the specified target.
# E.g.
# z3_append_linker_flag_list_to_target(mytarget "-fopenmp" "-static")
function(z3_append_linker_flag_list_to_target target)
if (NOT (TARGET "${target}"))
message(FATAL_ERROR "Specified target \"${target}\" is not a target")
endif()
foreach(flag ${ARGN})
#message(STATUS "Appending link flag \"${flag}\" to target ${target}")
# Note that space inside the quoted string is required so that the flags
# are space separated.
set_property(TARGET ${target} APPEND_STRING PROPERTY LINK_FLAGS " ${flag}")
endforeach()
endfunction()