diff --git a/.gitignore b/.gitignore index 5e220ba02..635c1947c 100755 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,10 @@ *.idb *.pdb +build/* +build32/* +vsbuild/* + *libtool.m4 *ltoptions.m4 *ltsugar.m4 @@ -125,8 +129,10 @@ _CppBlockUtils.* /.settings /*.wallet -/findpass.py /*.txt +!CMakeLists.txt + +/findpass.py /sandbox.py /lang/*.qm diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 000000000..7a51a5283 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,51 @@ +cmake_minimum_required(VERSION 2.8.12) # ubuntu 14 version + +set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake) + +set(VCPKG_DEPS protobuf openssl libwebsockets) + +include(Set-Toolchain-vcpkg) + +project(BitcoinArmory C CXX) + +if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "release build with debug info" FORCE) +endif() + +if(POLICY CMP0077) + cmake_policy(SET CMP0077 NEW) +endif() + +include(ArmorySupport) +include(PrettyCompilerColors) + +use_cxx11() + +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +# use ccache if available, and not already enabled on the command line +# but not with ninja and msys ccache on msys2 +if(NOT (WIN32 AND (NOT $ENV{MSYSTEM} STREQUAL "") AND CMAKE_GENERATOR STREQUAL Ninja)) + if(NOT CMAKE_CXX_COMPILER_LAUNCHER AND NOT CMAKE_C_COMPILER_LAUNCHER) + find_program(CCACHE_FOUND ccache) + if(CCACHE_FOUND) + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE ccache) + set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK ccache) + endif(CCACHE_FOUND) + endif() +endif() + +# build for host CPU if desired (default yes) +option(WITH_HOST_CPU_FEATURES "support the CPU features of the build host, gcc only" ON) + +if(WITH_HOST_CPU_FEATURES AND CMAKE_CXX_COMPILER_ID STREQUAL GNU) + check_x86_cpu_features() + + add_compile_options(-march=native ${X86_CPU_FEATURES_COMPILER_FLAGS}) +endif() + +if(MSVC) + add_compile_definitions(NOMINMAX _WINSOCKAPI_) +endif() + +add_subdirectory(cppForSwig) diff --git a/CMakeSettings.json b/CMakeSettings.json new file mode 100644 index 000000000..28ca9987c --- /dev/null +++ b/CMakeSettings.json @@ -0,0 +1,53 @@ +{ + "configurations": [ + { + "name": "x64-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ + "msvc_x64" + ], + "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", + "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", + "cmakeCommandArgs": "-DVCPKG_TRIPLET=x64-windows", + "buildCommandArgs": "-v", + "ctestCommandArgs": "" + }, { + "name": "x64-Release", + "generator": "Ninja", + "configurationType": "Release", + "inheritEnvironments": [ + "msvc_x64" + ], + "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", + "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", + "cmakeCommandArgs": "-DVCPKG_TRIPLET=x64-windows", + "buildCommandArgs": "-v", + "ctestCommandArgs": "" + }, { + "name": "x86-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ + "msvc_x86" + ], + "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", + "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", + "cmakeCommandArgs": "-DVCPKG_TRIPLET=x86-windows", + "buildCommandArgs": "-v", + "ctestCommandArgs": "" + }, { + "name": "x86-Release", + "generator": "Ninja", + "configurationType": "Release", + "inheritEnvironments": [ + "msvc_x86" + ], + "buildRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\build\\${name}", + "installRoot": "${env.USERPROFILE}\\CMakeBuilds\\${workspaceHash}\\install\\${name}", + "cmakeCommandArgs": "-DVCPKG_TRIPLET=x86-windows", + "buildCommandArgs": "-v", + "ctestCommandArgs": "" + } + ] +} diff --git a/README.md b/README.md index b306f53c2..02453722a 100644 --- a/README.md +++ b/README.md @@ -16,32 +16,20 @@ Multi-signature transactions are accommodated under-the-hood about 80%, and will ## Building Armory From Source -[Instructions for Windows](windowsbuild/Windows_build_notes.md) -[Instructions for macOS](osxbuild/macOS_build_notes.md) -[Instructions for Ubuntu and Arch Linux](linuxbuild/Linux_build_notes.md) - ### Dependencies * GNU Compiler Collection Linux: Install package `g++` -* Crypto++ - Linux: Install package `libcrypto++-dev` - Windows: [Download](https://www.cryptopp.com/#download) - * SWIG Linux: Install package `swig` - Windows: [Download](http://www.swig.org/download.html) + Windows: [Download](http://www.swig.org/download.html) MSVS: Copy swigwin-2.x directory next to cryptopp as `swigwin` * Python 2.6/2.7 Linux: Install package `python-dev` Windows: [Download](https://www.python.org/getit/) -* Python Twisted -- asynchronous networking - Linux: Install package `python-twisted` - Windows: [Download](https://twistedmatrix.com/trac/wiki/Downloads) - * PyQt 4 (for Python 2.X) Linux: Install packages `libqtcore4`, `libqt4-dev`, `python-qt4`, and `pyqt4-dev-tools` Windows: [Download](https://riverbankcomputing.com/software/pyqt/download) @@ -50,19 +38,48 @@ Multi-signature transactions are accommodated under-the-hood about 80%, and will (OPTIONAL - if you want to make a standalone executable in Windows) Windows: [Download](http://www.py2exe.org/) -* LMDB - database engine, modified to suit Armory's use cases -[LMDB page](http://symas.com/mdb/) - No need for external installs by Armory users - * libwebsockets - Linux: Final instructions TBA. - Windows: Follow the "Windows binary build" directions [here](https://github.com/warmcat/libwebsockets/blob/master/README.md). + Linux: install latest version from source + Windows: handled automatically with vcpkg, see below * Google Protocol Buffers (protobuf) Linux: Install the `protobuf` package. - Windows: Follow the "C++ Installation - Windows" directions [here](https://github.com/google/protobuf/blob/master/src/README.md), downloading only the `protoc` binary. - -* macOS - [Instructions for downloading, verifying, and running Armory on macOS](README_macOS.md). + Windows: handled automatically with vcpkg, see below + +### CMake options + +| **Option** | **Description** | **Default** | +|-----------------------------|------------------------------------------------------------------------------------------|--------------------------------| +| WITH_HOST_CPU_FEATURES | use -march=native and supported cpu feature flags, gcc only | ON | +| WITH_CRYPTOPP | use Crypto++ library for cryptography functions | OFF | +| WITH_CLIENT | build Python client | AUTO | +| WITH_GUI | build GUI support using Qt4 for the Python client | AUTO | +| ENABLE_TESTS | build the test binaries | OFF | +| LIBBTC_WITH_WALLET | enable libbtc wallet | OFF | +| LIBBTC_WITH_TESTS | enable libbtc tests | OFF | +| LIBBTC_WITH_TOOLS | build libbtc tools binaries | OFF | +| LIBBTC_RANDOM_DEVICE | device to use for random numbers | /dev/urandom | +| SECP256K1_ENABLE_ASM | enable asm routines in the secp256k1 library | ON | +| SECP256K1_USE_LIBGMP | use libgmp for numeric routines in the secp256k1 library | AUTO | +| SECP256K1_MODULE_ECDH | enable the ecdh module in the secp256k1 library | OFF | +| SECP256K1_MODULE_SCHNORR | enable the schnorr module in the secp256k1 library | OFF | +| SECP256K1_ECMULT_STATIC_PRECOMPUTATION | use a statically generated ecmult table for the secp256k1 library | OFF | +| SECP256K1_ENDOMORPHISM | use endomorphism optiomization for the secp256k1 library | OFF | +| SECP256K1_WITH_FIELD | field for the secp256k1 library, can be '32bit', '64bit' or 'AUTO' | AUTO | +| SECP256K1_WITH_SCALAR | scalar for the secp256k1 library, can be '32bit', '64bit' or 'AUTO' | AUTO | +| VCPKG_TARGET_TRIPLET | see below | not set | + +### CMake Windows/vcpkg Build Type + +When building on windows, set the cmake variable `VCPKG_TARGET_TRIPLET` to +`x64-windows` or `x86-windows` depending on whether the build is for 64 bit or +32 bit. You must be in the appropriate Visual Studio environment as well. + +All vcpkg supported triplets should work, and this variable can be used to +activate vcpkg support on other platforms. + +When building with the Visual Studio IDE, the build products will be located +under `C:\Users\\CMakeBuilds`. ## Sample Code diff --git a/cmake/ArmorySupport.cmake b/cmake/ArmorySupport.cmake new file mode 100644 index 000000000..16cef97a2 --- /dev/null +++ b/cmake/ArmorySupport.cmake @@ -0,0 +1,91 @@ +# random utility functions/macros + +# make sure architecture is set +if(NOT CMAKE_SYSTEM_PROCESSOR) + if(NOT CMAKE_TOOLCHAIN_FILE AND CMAKE_HOST_SYSTEM_PROCESSOR) + set(CMAKE_SYSTEM_PROCESSOR ${CMAKE_HOST_SYSTEM_PROCESSOR}) + elseif(CMAKE_TOOLCHAIN_FILE MATCHES mxe) + if(CMAKE_TOOLCHAIN_FILE MATCHES "i[3-9]86") + set(CMAKE_SYSTEM_PROCESSOR i686) + else() + set(CMAKE_SYSTEM_PROCESSOR x86_64) + endif() + endif() +endif() + +macro(string_option opt doc_string initial_value) + if(NOT DEFINED ${${opt}}) + set(${opt} ${initial_value}) + endif() + + set(${opt} ${${opt}} CACHE STRING ${doc_string}) +endmacro() + +# This is from: +# https://stackoverflow.com/a/31010221 +macro(use_cxx11) + if (CMAKE_VERSION VERSION_LESS 3.1) + if(CMAKE_CXX_COMPILER_ID STREQUAL GNU OR CMAKE_CXX_COMPILER_ID STREQUAL Clang) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11") + endif() + else() + # Fix behavior of CMAKE_CXX_STANDARD when targeting macOS. + if(POLICY CMP0025) + cmake_policy(SET CMP0025 NEW) + endif() + + set(CMAKE_CXX_STANDARD 11) + endif() +endmacro(use_cxx11) + +unset(X86_CPU_FEATURES_COMPILER_FLAGS) + +# check for x86 cpu features and sets X86_CPU_FEATURES_COMPILER_FLAGS for gcc/clang +function(check_x86_cpu_features) + if(NOT CMAKE_SYSTEM_PROCESSOR MATCHES "i.86|x86_64") + return() + endif() + + if(DEFINED X86_CPU_FEATURES_COMPILER_FLAGS) # already computed, do nothing + return() + endif() + + include(CheckCXXSourceCompiles) + + check_cxx_source_compiles(" + #include + + int main(int argc, char** argv) + { + __builtin_cpu_init(); + } + " HAVE_CPU_INIT) + + if(HAVE_CPU_INIT) + include(CheckCXXSourceRuns) + + foreach(cpu_feature mmx popcnt sse sse2 sse3 sse4.1 sse4.2 sse4a avx avx2 avx512f fma fma4 bmi bmi2) + string(REPLACE . _ cpu_feature_var ${cpu_feature}) + + check_cxx_source_runs(" + #include + + int main(int argc, char** argv) + { + __builtin_cpu_init(); + + if (__builtin_cpu_supports(\"${cpu_feature}\")) + return 0; + + return 1; + } + " HAVE_${cpu_feature_var}) + + if(HAVE_${cpu_feature_var}) + list(APPEND X86_CPU_FEATURES_COMPILER_FLAGS -m${cpu_feature}) + endif() + endforeach() + + set(X86_CPU_FEATURES_COMPILER_FLAGS ${X86_CPU_FEATURES_COMPILER_FLAGS} CACHE STRING "gcc/clang cpu feature flags for the build host" FORCE) + endif() +endfunction() diff --git a/cmake/FindPython/Support.cmake b/cmake/FindPython/Support.cmake new file mode 100644 index 000000000..f1ee341a9 --- /dev/null +++ b/cmake/FindPython/Support.cmake @@ -0,0 +1,1267 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +# +# This file is a "template" file used by various FindPython modules. +# + +cmake_policy (VERSION 3.7) + +# +# Initial configuration +# +if (NOT DEFINED _PYTHON_PREFIX) + message (FATAL_ERROR "FindPython: INTERNAL ERROR") +endif() +if (NOT DEFINED _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) + message (FATAL_ERROR "FindPython: INTERNAL ERROR") +endif() +if (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL 3) + set(_${_PYTHON_PREFIX}_VERSIONS 3.8 3.7 3.6 3.5 3.4 3.3 3.2 3.1 3.0) +elseif (_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR EQUAL 2) + set(_${_PYTHON_PREFIX}_VERSIONS 2.7 2.6 2.5 2.4 2.3 2.2 2.1 2.0) +else() + message (FATAL_ERROR "FindPython: INTERNAL ERROR") +endif() + + +# +# helper commands +# +macro (_PYTHON_DISPLAY_FAILURE _PYTHON_MSG) + if (${_PYTHON_PREFIX}_FIND_REQUIRED) + message (FATAL_ERROR "${_PYTHON_MSG}") + else() + if (NOT ${_PYTHON_PREFIX}_FIND_QUIETLY) + message(STATUS "${_PYTHON_MSG}") + endif () + endif() + + set (${_PYTHON_PREFIX}_FOUND FALSE) + string (TOUPPER "${_PYTHON_PREFIX}" _${_PYTHON_PREFIX}_UPPER_PREFIX) + set (${_PYTHON_UPPER_PREFIX}_FOUND FALSE) + return() +endmacro() + + +macro (_PYTHON_FIND_FRAMEWORKS) + set (${_PYTHON_PREFIX}_FRAMEWORKS) + if (APPLE) + set (_pff_frameworks ${CMAKE_FRAMEWORK_PATH} + $ENV{CMAKE_FRAMEWORK_PATH} + ~/Library/Frameworks + /usr/local/Frameworks + ${CMAKE_SYSTEM_FRAMEWORK_PATH}) + list (REMOVE_DUPLICATES _pff_frameworks) + foreach (_pff_framework IN LISTS _pff_frameworks) + if (EXISTS ${_pff_framework}/Python.framework) + list (APPEND ${_PYTHON_PREFIX}_FRAMEWORKS ${_pff_framework}/Python.framework) + endif() + endforeach() + unset (_pff_frameworks) + unset (_pff_framework) + endif() +endmacro() + +function (_PYTHON_GET_FRAMEWORKS _PYTHON_PGF_FRAMEWORK_PATHS _PYTHON_VERSION) + set (_PYTHON_FRAMEWORK_PATHS) + foreach (_PYTHON_FRAMEWORK IN LISTS ${_PYTHON_PREFIX}_FRAMEWORKS) + list (APPEND _PYTHON_FRAMEWORK_PATHS + "${_PYTHON_FRAMEWORK}/Versions/${_PYTHON_VERSION}") + endforeach() + set (${_PYTHON_PGF_FRAMEWORK_PATHS} ${_PYTHON_FRAMEWORK_PATHS} PARENT_SCOPE) +endfunction() + + +function (_PYTHON_VALIDATE_INTERPRETER) + if (NOT ${_PYTHON_PREFIX}_EXECUTABLE) + return() + endif() + + if (ARGC EQUAL 1) + set (expected_version ${ARGV0}) + else() + unset (expected_version) + endif() + + get_filename_component (python_name "${${_PYTHON_PREFIX}_EXECUTABLE}" NAME) + + if (expected_version AND NOT python_name STREQUAL "python${expected_version}${CMAKE_EXECUTABLE_SUFFIX}") + # executable found must have a specific version + execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c + "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:2]]))" + RESULT_VARIABLE result + OUTPUT_VARIABLE version + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (result OR NOT version EQUAL expected_version) + # interpreter not usable or has wrong major version + set (${_PYTHON_PREFIX}_EXECUTABLE ${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND CACHE INTERNAL "" FORCE) + return() + endif() + else() + if (NOT python_name STREQUAL "python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}${CMAKE_EXECUTABLE_SUFFIX}") + # executable found do not have version in name + # ensure major version is OK + execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c + "import sys; sys.stdout.write(str(sys.version_info[0]))" + RESULT_VARIABLE result + OUTPUT_VARIABLE version + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (result OR NOT version EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) + # interpreter not usable or has wrong major version + set (${_PYTHON_PREFIX}_EXECUTABLE ${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND CACHE INTERNAL "" FORCE) + return() + endif() + endif() + endif() + + if (CMAKE_SIZEOF_VOID_P AND "Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS + AND NOT CMAKE_CROSSCOMPILING) + # In this case, interpreter must have same architecture as environment + execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c + "import sys, struct; sys.stdout.write(str(struct.calcsize(\"P\")))" + RESULT_VARIABLE result + OUTPUT_VARIABLE size + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (result OR NOT size EQUAL CMAKE_SIZEOF_VOID_P) + # interpreter not usable or has wrong architecture + set (${_PYTHON_PREFIX}_EXECUTABLE ${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND CACHE INTERNAL "" FORCE) + return() + endif() + endif() +endfunction() + + +function (_PYTHON_VALIDATE_COMPILER expected_version) + if (NOT ${_PYTHON_PREFIX}_COMPILER) + return() + endif() + + # retrieve python environment version from compiler + set (working_dir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir") + file (WRITE "${working_dir}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:2]]))\n") + execute_process (COMMAND "${${_PYTHON_PREFIX}_COMPILER}" /target:exe /embed "${working_dir}/version.py" + WORKING_DIRECTORY "${working_dir}" + OUTPUT_QUIET + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + execute_process (COMMAND "${working_dir}/version" + WORKING_DIRECTORY "${working_dir}" + RESULT_VARIABLE result + OUTPUT_VARIABLE version + ERROR_QUIET) + file (REMOVE_RECURSE "${_${_PYTHON_PREFIX}_VERSION_DIR}") + + if (result OR NOT version EQUAL expected_version) + # Compiler not usable or has wrong major version + set (${_PYTHON_PREFIX}_COMPILER ${_PYTHON_PREFIX}_COMPILER-NOTFOUND CACHE INTERNAL "" FORCE) + endif() +endfunction() + + +function (_PYTHON_FIND_RUNTIME_LIBRARY _PYTHON_LIB) + string (REPLACE "_RUNTIME" "" _PYTHON_LIB "${_PYTHON_LIB}") + # look at runtime part on systems supporting it + if (CMAKE_SYSTEM_NAME STREQUAL "Windows" OR + (CMAKE_SYSTEM_NAME MATCHES "MSYS|CYGWIN" + AND ${_PYTHON_LIB} MATCHES "${CMAKE_IMPORT_LIBRARY_SUFFIX}$")) + set (CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_SHARED_LIBRARY_SUFFIX}) + # MSYS has a special syntax for runtime libraries + if (CMAKE_SYSTEM_NAME MATCHES "MSYS") + list (APPEND CMAKE_FIND_LIBRARY_PREFIXES "msys-") + endif() + find_library (${ARGV}) + endif() +endfunction() + + +function (_PYTHON_SET_LIBRARY_DIRS _PYTHON_SLD_RESULT) + unset (_PYTHON_DIRS) + set (_PYTHON_LIBS ${ARGV}) + list (REMOVE_AT _PYTHON_LIBS 0) + foreach (_PYTHON_LIB IN LISTS _PYTHON_LIBS) + if (${_PYTHON_LIB}) + get_filename_component (_PYTHON_DIR "${${_PYTHON_LIB}}" DIRECTORY) + list (APPEND _PYTHON_DIRS "${_PYTHON_DIR}") + endif() + endforeach() + if (_PYTHON_DIRS) + list (REMOVE_DUPLICATES _PYTHON_DIRS) + endif() + set (${_PYTHON_SLD_RESULT} ${_PYTHON_DIRS} PARENT_SCOPE) +endfunction() + + +# If major version is specified, it must be the same as internal major version +if (DEFINED ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR + AND NOT ${_PYTHON_PREFIX}_FIND_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) + _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Wrong major version specified is \"${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}\", but expected major version is \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"") +endif() + + +# handle components +if (NOT ${_PYTHON_PREFIX}_FIND_COMPONENTS) + set (${_PYTHON_PREFIX}_FIND_COMPONENTS Interpreter) + set (${_PYTHON_PREFIX}_FIND_REQUIRED_Interpreter TRUE) +endif() +foreach (_${_PYTHON_PREFIX}_COMPONENT IN LISTS ${_PYTHON_PREFIX}_FIND_COMPONENTS) + set (${_PYTHON_PREFIX}_${_${_PYTHON_PREFIX}_COMPONENT}_FOUND FALSE) +endforeach() +unset (_${_PYTHON_PREFIX}_FIND_VERSIONS) + +# Set versions to search +## default: search any version +set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSIONS}) + +if (${_PYTHON_PREFIX}_FIND_VERSION_COUNT GREATER 1) + if (${_PYTHON_PREFIX}_FIND_VERSION_EXACT) + set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_FIND_VERSION_MAJOR}.${${_PYTHON_PREFIX}_FIND_VERSION_MINOR}) + else() + unset (_${_PYTHON_PREFIX}_FIND_VERSIONS) + # add all compatible versions + foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_VERSIONS) + if (_${_PYTHON_PREFIX}_VERSION VERSION_GREATER_EQUAL ${_PYTHON_PREFIX}_FIND_VERSION) + list (APPEND _${_PYTHON_PREFIX}_FIND_VERSIONS ${_${_PYTHON_PREFIX}_VERSION}) + endif() + endforeach() + endif() +endif() + +# Python and Anaconda distributions: define which architectures can be used +if (CMAKE_SIZEOF_VOID_P) + # In this case, search only for 64bit or 32bit + math (EXPR _${_PYTHON_PREFIX}_ARCH "${CMAKE_SIZEOF_VOID_P} * 8") + set (_${_PYTHON_PREFIX}_ARCH2 ${_${_PYTHON_PREFIX}_ARCH}) +else() + # architecture unknown, search for both 64bit and 32bit + set (_${_PYTHON_PREFIX}_ARCH 64) + set (_${_PYTHON_PREFIX}_ARCH2 32) +endif() + +# IronPython support +if (CMAKE_SIZEOF_VOID_P) + # In this case, search only for 64bit or 32bit + math (EXPR _${_PYTHON_PREFIX}_ARCH "${CMAKE_SIZEOF_VOID_P} * 8") + set (_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES ipy${_${_PYTHON_PREFIX}_ARCH} ipy) +else() + # architecture unknown, search for natural interpreter + set (_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES ipy) +endif() +set (_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES net45 net40) + +# Apple frameworks handling +_python_find_frameworks () + +# Save CMAKE_FIND_APPBUNDLE +if (DEFINED CMAKE_FIND_APPBUNDLE) + set (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE ${CMAKE_FIND_APPBUNDLE}) +else() + unset (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE) +endif() +# To avoid app bundle lookup +set (CMAKE_FIND_APPBUNDLE "NEVER") + +# Save CMAKE_FIND_FRAMEWORK +if (DEFINED CMAKE_FIND_FRAMEWORK) + set (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK}) + if (CMAKE_FIND_FRAMEWORK STREQUAL "ONLY") + message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: CMAKE_FIND_FRAMEWORK: 'ONLY' value is not supported. 'FIRST' will be used instead.") + set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK "FIRST") + else() + set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK ${CMAKE_FIND_FRAMEWORK}) + endif() +else() + unset (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK) + set (_${_PYTHON_PREFIX}_FIND_FRAMEWORK "FIRST") +endif() +# To avoid framework lookup +set (CMAKE_FIND_FRAMEWORK "NEVER") + +# Windows Registry handling +if (DEFINED ${_PYTHON_PREFIX}_FIND_REGISTRY) + if (NOT ${_PYTHON_PREFIX}_FIND_REGISTRY MATCHES "^(FIRST|LAST|NEVER)$") + message (AUTHOR_WARNING "Find${_PYTHON_PREFIX}: ${${_PYTHON_PREFIX}_FIND_REGISTRY}: invalid value for '${_PYTHON_PREFIX}_FIND_REGISTRY'. 'FIRST', 'LAST' or 'NEVER' expected.") + set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST") + else() + set (_${_PYTHON_PREFIX}_FIND_REGISTRY ${${_PYTHON_PREFIX}_FIND_REGISTRY}) + endif() +else() + set (_${_PYTHON_PREFIX}_FIND_REGISTRY "FIRST") +endif() + + +unset (_${_PYTHON_PREFIX}_REQUIRED_VARS) +unset (_${_PYTHON_PREFIX}_CACHED_VARS) + + +# first step, search for the interpreter +if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) + if (${_PYTHON_PREFIX}_FIND_REQUIRED_Interpreter) + list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_EXECUTABLE) + list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS ${_PYTHON_PREFIX}_EXECUTABLE) + endif() + + set (_${_PYTHON_PREFIX}_HINTS "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR) + + # look-up for various versions and locations + foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) + string (REPLACE "." "" _${_PYTHON_PREFIX}_VERSION_NO_DOTS ${_${_PYTHON_PREFIX}_VERSION}) + + _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION}) + + # Apple frameworks handling + if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") + find_program (${_PYTHON_PREFIX}_EXECUTABLE + NAMES python${_${_PYTHON_PREFIX}_VERSION} + python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + NAMES_PER_DIR + PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} + PATH_SUFFIXES bin + NO_CMAKE_PATH + NO_CMAKE_ENVIRONMENT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + + # Windows registry + if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") + find_program (${_PYTHON_PREFIX}_EXECUTABLE + NAMES python${_${_PYTHON_PREFIX}_VERSION} + python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + python + ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} + NAMES_PER_DIR + HINTS ${_${_PYTHON_PREFIX}_HINTS} + PATHS [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + + # try using HINTS + find_program (${_PYTHON_PREFIX}_EXECUTABLE + NAMES python${_${_PYTHON_PREFIX}_VERSION} + python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + python + ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} + NAMES_PER_DIR + HINTS ${_${_PYTHON_PREFIX}_HINTS} + PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + # try using standard paths. + if (WIN32) + find_program (${_PYTHON_PREFIX}_EXECUTABLE + NAMES python${_${_PYTHON_PREFIX}_VERSION} + python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + python + ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} + NAMES_PER_DIR) + else() + find_program (${_PYTHON_PREFIX}_EXECUTABLE + NAMES python${_${_PYTHON_PREFIX}_VERSION} + python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + NAMES_PER_DIR) + endif() + + # Apple frameworks handling + if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") + find_program (${_PYTHON_PREFIX}_EXECUTABLE + NAMES python${_${_PYTHON_PREFIX}_VERSION} + python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + NAMES_PER_DIR + PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} + PATH_SUFFIXES bin + NO_DEFAULT_PATH) + endif() + + # Windows registry + if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") + find_program (${_PYTHON_PREFIX}_EXECUTABLE + NAMES python${_${_PYTHON_PREFIX}_VERSION} + python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + python + ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} + NAMES_PER_DIR + PATHS [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} + NO_DEFAULT_PATH) + endif() + + _python_validate_interpreter (${_${_PYTHON_PREFIX}_VERSION}) + if (${_PYTHON_PREFIX}_EXECUTABLE) + break() + endif() + endforeach() + + if (NOT ${_PYTHON_PREFIX}_EXECUTABLE) + # No specific version found. Retry with generic names + # try using HINTS + find_program (${_PYTHON_PREFIX}_EXECUTABLE + NAMES python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + python + ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES} + NAMES_PER_DIR + HINTS ${_${_PYTHON_PREFIX}_HINTS} + PATH_SUFFIXES bin ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + # try using standard paths. + # NAMES_PER_DIR is not defined on purpose to have a chance to find + # expected version. + # For example, typical systems have 'python' for version 2.* and 'python3' + # for version 3.*. So looking for names per dir will find, potentially, + # systematically 'python' (i.e. version 2) even if version 3 is searched. + find_program (${_PYTHON_PREFIX}_EXECUTABLE + NAMES python${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR} + python + ${_${_PYTHON_PREFIX}_IRON_PYTHON_NAMES}) + + _python_validate_interpreter () + endif() + + # retrieve exact version of executable found + if (${_PYTHON_PREFIX}_EXECUTABLE) + execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c + "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))" + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE ${_PYTHON_PREFIX}_VERSION + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (NOT _${_PYTHON_PREFIX}_RESULT) + string (REGEX MATCHALL "[0-9]+" _${_PYTHON_PREFIX}_VERSIONS "${${_PYTHON_PREFIX}_VERSION}") + list (GET _${_PYTHON_PREFIX}_VERSIONS 0 ${_PYTHON_PREFIX}_VERSION_MAJOR) + list (GET _${_PYTHON_PREFIX}_VERSIONS 1 ${_PYTHON_PREFIX}_VERSION_MINOR) + list (GET _${_PYTHON_PREFIX}_VERSIONS 2 ${_PYTHON_PREFIX}_VERSION_PATCH) + else() + # Interpreter is not usable + set (${_PYTHON_PREFIX}_EXECUTABLE ${_PYTHON_PREFIX}_EXECUTABLE-NOTFOUND CACHE INTERNAL "" FORCE) + unset (${_PYTHON_PREFIX}_VERSION) + endif() + endif() + + if (${_PYTHON_PREFIX}_EXECUTABLE + AND ${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) + set (${_PYTHON_PREFIX}_Interpreter_FOUND TRUE) + # Use interpreter version for future searches to ensure consistency + set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}) + endif() + + if (${_PYTHON_PREFIX}_Interpreter_FOUND) + if (NOT CMAKE_SIZEOF_VOID_P) + # determine interpreter architecture + execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; print(sys.maxsize > 2**32)" + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE ${_PYTHON_PREFIX}_IS64BIT + ERROR_VARIABLE ${_PYTHON_PREFIX}_IS64BIT) + if (NOT _${_PYTHON_PREFIX}_RESULT) + if (${_PYTHON_PREFIX}_IS64BIT) + set (_${_PYTHON_PREFIX}_ARCH 64) + set (_${_PYTHON_PREFIX}_ARCH2 64) + else() + set (_${_PYTHON_PREFIX}_ARCH 32) + set (_${_PYTHON_PREFIX}_ARCH2 32) + endif() + endif() + endif() + + # retrieve interpreter identity + execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -V + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID + ERROR_VARIABLE ${_PYTHON_PREFIX}_INTERPRETER_ID) + if (NOT _${_PYTHON_PREFIX}_RESULT) + if (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Anaconda") + set (${_PYTHON_PREFIX}_INTERPRETER_ID "Anaconda") + elseif (${_PYTHON_PREFIX}_INTERPRETER_ID MATCHES "Enthought") + set (${_PYTHON_PREFIX}_INTERPRETER_ID "Canopy") + else() + string (REGEX REPLACE "^([^ ]+).*" "\\1" ${_PYTHON_PREFIX}_INTERPRETER_ID "${${_PYTHON_PREFIX}_INTERPRETER_ID}") + if (${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "Python") + # try to get a more precise ID + execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; print(sys.copyright)" + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE ${_PYTHON_PREFIX}_COPYRIGHT + ERROR_QUIET) + if (${_PYTHON_PREFIX}_COPYRIGHT MATCHES "ActiveState") + set (${_PYTHON_PREFIX}_INTERPRETER_ID "ActivePython") + endif() + endif() + endif() + else() + set (${_PYTHON_PREFIX}_INTERPRETER_ID Python) + endif() + else() + unset (${_PYTHON_PREFIX}_INTERPRETER_ID) + endif() + + # retrieve various package installation directories + execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c "import sys; from distutils import sysconfig;sys.stdout.write(';'.join([sysconfig.get_python_lib(plat_specific=False,standard_lib=True),sysconfig.get_python_lib(plat_specific=True,standard_lib=True),sysconfig.get_python_lib(plat_specific=False,standard_lib=False),sysconfig.get_python_lib(plat_specific=True,standard_lib=False)]))" + + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE _${_PYTHON_PREFIX}_LIBPATHS + ERROR_QUIET) + if (NOT _${_PYTHON_PREFIX}_RESULT) + list (GET _${_PYTHON_PREFIX}_LIBPATHS 0 ${_PYTHON_PREFIX}_STDLIB) + list (GET _${_PYTHON_PREFIX}_LIBPATHS 1 ${_PYTHON_PREFIX}_STDARCH) + list (GET _${_PYTHON_PREFIX}_LIBPATHS 2 ${_PYTHON_PREFIX}_SITELIB) + list (GET _${_PYTHON_PREFIX}_LIBPATHS 3 ${_PYTHON_PREFIX}_SITEARCH) + else() + unset (${_PYTHON_PREFIX}_STDLIB) + unset (${_PYTHON_PREFIX}_STDARCH) + unset (${_PYTHON_PREFIX}_SITELIB) + unset (${_PYTHON_PREFIX}_SITEARCH) + endif() + + mark_as_advanced (${_PYTHON_PREFIX}_EXECUTABLE) +endif() + + +# second step, search for compiler (IronPython) +if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS) + if (${_PYTHON_PREFIX}_FIND_REQUIRED_Compiler) + list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_COMPILER) + list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS ${_PYTHON_PREFIX}_COMPILER) + endif() + + # IronPython specific artifacts + # If IronPython interpreter is found, use its path + unset (_${_PYTHON_PREFIX}_IRON_ROOT) + if (${_PYTHON_PREFIX}_Interpreter_FOUND AND ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "IronPython") + get_filename_component (_${_PYTHON_PREFIX}_IRON_ROOT "${${_PYTHON_PREFIX}_EXECUTABLE}" DIRECTORY) + endif() + + # try using root dir and registry + foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) + if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") + find_program (${_PYTHON_PREFIX}_COMPILER + NAMES ipyc + HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} + PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + + find_program (${_PYTHON_PREFIX}_COMPILER + NAMES ipyc + HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} + PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + + if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") + find_program (${_PYTHON_PREFIX}_COMPILER + NAMES ipyc + PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\IronPython\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES} + NO_DEFAULT_PATH) + endif() + + _python_validate_compiler (${_${_PYTHON_PREFIX}_VERSION}) + if (${_PYTHON_PREFIX}_COMPILER) + break() + endif() + endforeach() + + # no specific version found, re-try in standard paths + find_program (${_PYTHON_PREFIX}_COMPILER + NAMES ipyc + HINTS ${_${_PYTHON_PREFIX}_IRON_ROOT} ${_${_PYTHON_PREFIX}_HINTS} + PATH_SUFFIXES ${_${_PYTHON_PREFIX}_IRON_PYTHON_PATH_SUFFIXES}) + + if (${_PYTHON_PREFIX}_COMPILER) + # retrieve python environment version from compiler + set (_${_PYTHON_PREFIX}_VERSION_DIR "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/PythonCompilerVersion.dir") + file (WRITE "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py" "import sys; sys.stdout.write('.'.join([str(x) for x in sys.version_info[:3]]))\n") + execute_process (COMMAND "${${_PYTHON_PREFIX}_COMPILER}" /target:exe /embed "${_${_PYTHON_PREFIX}_VERSION_DIR}/version.py" + WORKING_DIRECTORY "${_${_PYTHON_PREFIX}_VERSION_DIR}" + OUTPUT_QUIET + ERROR_QUIET) + execute_process (COMMAND "${_${_PYTHON_PREFIX}_VERSION_DIR}/version" + WORKING_DIRECTORY "${_${_PYTHON_PREFIX}_VERSION_DIR}" + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE _${_PYTHON_PREFIX}_VERSION + ERROR_QUIET) + if (NOT _${_PYTHON_PREFIX}_RESULT) + string (REGEX MATCHALL "[0-9]+" _${_PYTHON_PREFIX}_VERSIONS "${_${_PYTHON_PREFIX}_VERSION}") + list (GET _${_PYTHON_PREFIX}_VERSIONS 0 _${_PYTHON_PREFIX}_VERSION_MAJOR) + list (GET _${_PYTHON_PREFIX}_VERSIONS 1 _${_PYTHON_PREFIX}_VERSION_MINOR) + list (GET _${_PYTHON_PREFIX}_VERSIONS 2 _${_PYTHON_PREFIX}_VERSION_PATCH) + + if (NOT ${_PYTHON_PREFIX}_Interpreter_FOUND) + # set public version information + set (${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_VERSION}) + set (${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_VERSION_MAJOR}) + set (${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_VERSION_MINOR}) + set (${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_VERSION_PATCH}) + endif() + else() + # compiler not usable + set (${_PYTHON_PREFIX}_COMPILER ${_PYTHON_PREFIX}_COMPILER-NOTFOUND CACHE INTERNAL "" FORCE) + endif() + file (REMOVE_RECURSE "${_${_PYTHON_PREFIX}_VERSION_DIR}") + endif() + + if (${_PYTHON_PREFIX}_COMPILER) + if (${_PYTHON_PREFIX}_Interpreter_FOUND) + # Compiler must be compatible with interpreter + if (${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR} VERSION_EQUAL ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}) + set (${_PYTHON_PREFIX}_Compiler_FOUND TRUE) + endif() + elseif (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) + set (${_PYTHON_PREFIX}_Compiler_FOUND TRUE) + # Use compiler version for future searches to ensure consistency + set (_${_PYTHON_PREFIX}_FIND_VERSIONS ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}) + endif() + endif() + + if (${_PYTHON_PREFIX}_Compiler_FOUND) + set (${_PYTHON_PREFIX}_COMPILER_ID IronPython) + else() + unset (${_PYTHON_PREFIX}_COMPILER_ID) + endif() + + mark_as_advanced (${_PYTHON_PREFIX}_COMPILER) +endif() + + +# third step, search for the development artifacts +## Development environment is not compatible with IronPython interpreter +if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS + AND NOT ${_PYTHON_PREFIX}_INTERPRETER_ID STREQUAL "IronPython") + if (${_PYTHON_PREFIX}_FIND_REQUIRED_Development) + list (APPEND _${_PYTHON_PREFIX}_REQUIRED_VARS ${_PYTHON_PREFIX}_LIBRARY + ${_PYTHON_PREFIX}_INCLUDE_DIR) + list (APPEND _${_PYTHON_PREFIX}_CACHED_VARS ${_PYTHON_PREFIX}_LIBRARY + ${_PYTHON_PREFIX}_LIBRARY_RELEASE + ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE + ${_PYTHON_PREFIX}_LIBRARY_DEBUG + ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG + ${_PYTHON_PREFIX}_INCLUDE_DIR) + endif() + + # Support preference of static libs by adjusting CMAKE_FIND_LIBRARY_SUFFIXES + unset (_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES) + if (DEFINED ${_PYTHON_PREFIX}_USE_STATIC_LIBS AND NOT WIN32) + set(_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + if(${_PYTHON_PREFIX}_USE_STATIC_LIBS) + set (CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) + else() + list (REMOVE_ITEM CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) + endif() + else() + endif() + + # if python interpreter is found, use its location and version to ensure consistency + # between interpreter and development environment + unset (_${_PYTHON_PREFIX}_PREFIX) + if (${_PYTHON_PREFIX}_Interpreter_FOUND) + execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c + "import sys; from distutils import sysconfig; sys.stdout.write(sysconfig.PREFIX)" + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE _${_PYTHON_PREFIX}_PREFIX + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (_${_PYTHON_PREFIX}_RESULT) + unset (_${_PYTHON_PREFIX}_PREFIX) + endif() + endif() + set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}" "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR) + + foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) + string (REPLACE "." "" _${_PYTHON_PREFIX}_VERSION_NO_DOTS ${_${_PYTHON_PREFIX}_VERSION}) + + # try to use pythonX.Y-config tool + set (_${_PYTHON_PREFIX}_CONFIG_NAMES) + if (DEFINED CMAKE_LIBRARY_ARCHITECTURE) + set (_${_PYTHON_PREFIX}_CONFIG_NAMES "${CMAKE_LIBRARY_ARCHITECTURE}-python${_${_PYTHON_PREFIX}_VERSION}-config") + endif() + list (APPEND _${_PYTHON_PREFIX}_CONFIG_NAMES "python${_${_PYTHON_PREFIX}_VERSION}-config") + find_program (_${_PYTHON_PREFIX}_CONFIG + NAMES ${_${_PYTHON_PREFIX}_CONFIG_NAMES} + NAMES_PER_DIR + HINTS ${_${_PYTHON_PREFIX}_HINTS} + PATH_SUFFIXES bin) + unset (_${_PYTHON_PREFIX}_CONFIG_NAMES) + + if (NOT _${_PYTHON_PREFIX}_CONFIG) + continue() + endif() + if (DEFINED CMAKE_LIBRARY_ARCHITECTURE) + # check that config tool match library architecture + execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --configdir + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE _${_PYTHON_PREFIX}_CONFIGDIR + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (_${_PYTHON_PREFIX}_RESULT) + unset (_${_PYTHON_PREFIX}_CONFIG CACHE) + continue() + endif() + string(FIND "${_${_PYTHON_PREFIX}_CONFIGDIR}" "${CMAKE_LIBRARY_ARCHITECTURE}" _${_PYTHON_PREFIX}_RESULT) + if (_${_PYTHON_PREFIX}_RESULT EQUAL -1) + unset (_${_PYTHON_PREFIX}_CONFIG CACHE) + continue() + endif() + endif() + + # retrieve root install directory + execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --prefix + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE _${_PYTHON_PREFIX}_PREFIX + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (_${_PYTHON_PREFIX}_RESULT) + # python-config is not usable + unset (_${_PYTHON_PREFIX}_CONFIG CACHE) + continue() + endif() + set (_${_PYTHON_PREFIX}_HINTS "${_${_PYTHON_PREFIX}_PREFIX}" "${${_PYTHON_PREFIX}_ROOT_DIR}" ENV ${_PYTHON_PREFIX}_ROOT_DIR) + + # retrieve library + execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --ldflags + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE _${_PYTHON_PREFIX}_FLAGS + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (NOT _${_PYTHON_PREFIX}_RESULT) + # retrieve library directory + string (REGEX MATCHALL "-L[^ ]+" _${_PYTHON_PREFIX}_LIB_DIRS "${_${_PYTHON_PREFIX}_FLAGS}") + string (REPLACE "-L" "" _${_PYTHON_PREFIX}_LIB_DIRS "${_${_PYTHON_PREFIX}_LIB_DIRS}") + list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_LIB_DIRS) + # retrieve library name + string (REGEX MATCHALL "-lpython[^ ]+" _${_PYTHON_PREFIX}_LIB_NAMES "${_${_PYTHON_PREFIX}_FLAGS}") + string (REPLACE "-l" "" _${_PYTHON_PREFIX}_LIB_NAMES "${_${_PYTHON_PREFIX}_LIB_NAMES}") + list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_LIB_NAMES) + + find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE + NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} + NAMES_PER_DIR + HINTS ${_${_PYTHON_PREFIX}_HINTS} ${_${_PYTHON_PREFIX}_LIB_DIRS} + PATH_SUFFIXES lib + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + # retrieve runtime library + if (${_PYTHON_PREFIX}_LIBRARY_RELEASE) + get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY) + _python_find_runtime_library (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE + NAMES ${_${_PYTHON_PREFIX}_LIB_NAMES} + NAMES_PER_DIR + HINTS ${_${_PYTHON_PREFIX}_PATH} ${_${_PYTHON_PREFIX}_HINTS} + PATH_SUFFIXES bin + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + endif() + + # retrieve include directory + execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --includes + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE _${_PYTHON_PREFIX}_FLAGS + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (NOT _${_PYTHON_PREFIX}_RESULT) + # retrieve include directory + string (REGEX MATCHALL "-I[^ ]+" _${_PYTHON_PREFIX}_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_FLAGS}") + string (REPLACE "-I" "" _${_PYTHON_PREFIX}_INCLUDE_DIRS "${_${_PYTHON_PREFIX}_INCLUDE_DIRS}") + list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_INCLUDE_DIRS) + + find_path (${_PYTHON_PREFIX}_INCLUDE_DIR + NAMES Python.h + HINTS ${_${_PYTHON_PREFIX}_INCLUDE_DIRS} + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + + if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_INCLUDE_DIR) + break() + endif() + endforeach() + + # Rely on HINTS and standard paths if config tool failed to locate artifacts + if (NOT (${_PYTHON_PREFIX}_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG) OR NOT ${_PYTHON_PREFIX}_INCLUDE_DIR) + foreach (_${_PYTHON_PREFIX}_VERSION IN LISTS _${_PYTHON_PREFIX}_FIND_VERSIONS) + string (REPLACE "." "" _${_PYTHON_PREFIX}_VERSION_NO_DOTS ${_${_PYTHON_PREFIX}_VERSION}) + + _python_get_frameworks (_${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_VERSION}) + + set (_${_PYTHON_PREFIX}_REGISTRY_PATHS + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + [HKEY_CURRENT_USER\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore\\${_${_PYTHON_PREFIX}_VERSION}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH}\\InstallPath] + [HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\ContinuumAnalytics\\Anaconda${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}-${_${_PYTHON_PREFIX}_ARCH2}\\InstallPath]) + + if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") + find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE + NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS} + python${_${_PYTHON_PREFIX}_VERSION}mu + python${_${_PYTHON_PREFIX}_VERSION}m + python${_${_PYTHON_PREFIX}_VERSION}u + python${_${_PYTHON_PREFIX}_VERSION} + NAMES_PER_DIR + PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} + PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}u + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION} + lib/python${_${_PYTHON_PREFIX}_VERSION}/config + NO_CMAKE_PATH + NO_CMAKE_ENVIRONMENT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + + if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") + find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE + NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS} + python${_${_PYTHON_PREFIX}_VERSION}mu + python${_${_PYTHON_PREFIX}_VERSION}m + python${_${_PYTHON_PREFIX}_VERSION}u + python${_${_PYTHON_PREFIX}_VERSION} + NAMES_PER_DIR + HINTS ${_${_PYTHON_PREFIX}_HINTS} + PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} + PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}u + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION} + lib/python${_${_PYTHON_PREFIX}_VERSION}/config + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + + # search in HINTS locations + find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE + NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS} + python${_${_PYTHON_PREFIX}_VERSION}mu + python${_${_PYTHON_PREFIX}_VERSION}m + python${_${_PYTHON_PREFIX}_VERSION}u + python${_${_PYTHON_PREFIX}_VERSION} + NAMES_PER_DIR + HINTS ${_${_PYTHON_PREFIX}_HINTS} + PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}u + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION} + lib/python${_${_PYTHON_PREFIX}_VERSION}/config + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + + if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "LAST") + set (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS}) + else() + unset (__${_PYTHON_PREFIX}_FRAMEWORK_PATHS) + endif() + + if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "LAST") + set (__${_PYTHON_PREFIX}_REGISTRY_PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS}) + else() + unset (__${_PYTHON_PREFIX}_REGISTRY_PATHS) + endif() + + # search in all default paths + find_library (${_PYTHON_PREFIX}_LIBRARY_RELEASE + NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS} + python${_${_PYTHON_PREFIX}_VERSION}mu + python${_${_PYTHON_PREFIX}_VERSION}m + python${_${_PYTHON_PREFIX}_VERSION}u + python${_${_PYTHON_PREFIX}_VERSION} + NAMES_PER_DIR + PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS} + ${__${_PYTHON_PREFIX}_REGISTRY_PATHS} + PATH_SUFFIXES lib/${CMAKE_LIBRARY_ARCHITECTURE} lib libs + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}mu + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}m + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION}u + lib/python${_${_PYTHON_PREFIX}_VERSION}/config-${_${_PYTHON_PREFIX}_VERSION} + lib/python${_${_PYTHON_PREFIX}_VERSION}/config) + # retrieve runtime library + if (${_PYTHON_PREFIX}_LIBRARY_RELEASE) + get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY) + _python_find_runtime_library (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE + NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS} + python${_${_PYTHON_PREFIX}_VERSION}mu + python${_${_PYTHON_PREFIX}_VERSION}m + python${_${_PYTHON_PREFIX}_VERSION}u + python${_${_PYTHON_PREFIX}_VERSION} + NAMES_PER_DIR + HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS} + PATH_SUFFIXES bin) + endif() + + if (WIN32) + # search for debug library + if (${_PYTHON_PREFIX}_LIBRARY_RELEASE) + # use library location as a hint + get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" DIRECTORY) + find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG + NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d + NAMES_PER_DIR + HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS} + NO_DEFAULT_PATH) + else() + # search first in known locations + if (_${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") + find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG + NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d + NAMES_PER_DIR + HINTS ${_${_PYTHON_PREFIX}_HINTS} + PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} + PATH_SUFFIXES lib libs + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + # search in all default paths + find_library (${_PYTHON_PREFIX}_LIBRARY_DEBUG + NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d + NAMES_PER_DIR + HINTS ${_${_PYTHON_PREFIX}_HINTS} + PATHS ${__${_PYTHON_PREFIX}_REGISTRY_PATHS} + PATH_SUFFIXES lib libs) + endif() + if (${_PYTHON_PREFIX}_LIBRARY_DEBUG) + get_filename_component (_${_PYTHON_PREFIX}_PATH "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}" DIRECTORY) + _python_find_runtime_library (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG + NAMES python${_${_PYTHON_PREFIX}_VERSION_NO_DOTS}_d + NAMES_PER_DIR + HINTS "${_${_PYTHON_PREFIX}_PATH}" ${_${_PYTHON_PREFIX}_HINTS} + PATH_SUFFIXES bin) + endif() + endif() + + # Don't search for include dir until library location is known + if (${_PYTHON_PREFIX}_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG) + unset (_${_PYTHON_PREFIX}_INCLUDE_HINTS) + + if (${_PYTHON_PREFIX}_EXECUTABLE) + # pick up include directory from configuration + execute_process (COMMAND "${${_PYTHON_PREFIX}_EXECUTABLE}" -c + "import sys; import sysconfig; sys.stdout.write(sysconfig.get_path('include'))" + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE _${_PYTHON_PREFIX}_PATH + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (NOT _${_PYTHON_PREFIX}_RESULT) + file (TO_CMAKE_PATH "${_${_PYTHON_PREFIX}_PATH}" _${_PYTHON_PREFIX}_PATH) + list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${_${_PYTHON_PREFIX}_PATH}") + endif() + endif() + + foreach (_${_PYTHON_PREFIX}_LIB IN ITEMS ${_PYTHON_PREFIX}_LIBRARY_RELEASE ${_PYTHON_PREFIX}_LIBRARY_DEBUG) + if (${_${_PYTHON_PREFIX}_LIB}) + # Use the library's install prefix as a hint + if (${_${_PYTHON_PREFIX}_LIB} MATCHES "^(.+/Frameworks/Python.framework/Versions/[0-9.]+)") + list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}") + elseif (${_${_PYTHON_PREFIX}_LIB} MATCHES "^(.+)/lib(64|32)?/python[0-9.]+/config") + list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}") + elseif (DEFINED CMAKE_LIBRARY_ARCHITECTURE AND ${_${_PYTHON_PREFIX}_LIB} MATCHES "^(.+)/lib/${CMAKE_LIBRARY_ARCHITECTURE}") + list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${CMAKE_MATCH_1}") + else() + # assume library is in a directory under root + get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${${_${_PYTHON_PREFIX}_LIB}}" DIRECTORY) + get_filename_component (_${_PYTHON_PREFIX}_PREFIX "${_${_PYTHON_PREFIX}_PREFIX}" DIRECTORY) + list (APPEND _${_PYTHON_PREFIX}_INCLUDE_HINTS "${_${_PYTHON_PREFIX}_PREFIX}") + endif() + endif() + endforeach() + list (REMOVE_DUPLICATES _${_PYTHON_PREFIX}_INCLUDE_HINTS) + + if (APPLE AND _${_PYTHON_PREFIX}_FIND_FRAMEWORK STREQUAL "FIRST") + find_path (${_PYTHON_PREFIX}_INCLUDE_DIR + NAMES Python.h + HINTS ${_${_PYTHON_PREFIX}_HINTS} + PATHS ${_${_PYTHON_PREFIX}_FRAMEWORK_PATHS} + PATH_SUFFIXES include/python${_${_PYTHON_PREFIX}_VERSION}mu + include/python${_${_PYTHON_PREFIX}_VERSION}m + include/python${_${_PYTHON_PREFIX}_VERSION}u + include/python${_${_PYTHON_PREFIX}_VERSION} + include + NO_CMAKE_PATH + NO_CMAKE_ENVIRONMENT_PATH + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + + if (WIN32 AND _${_PYTHON_PREFIX}_FIND_REGISTRY STREQUAL "FIRST") + find_path (${_PYTHON_PREFIX}_INCLUDE_DIR + NAMES Python.h + HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS} + PATHS ${_${_PYTHON_PREFIX}_REGISTRY_PATHS} + PATH_SUFFIXES include/python${_${_PYTHON_PREFIX}_VERSION}mu + include/python${_${_PYTHON_PREFIX}_VERSION}m + include/python${_${_PYTHON_PREFIX}_VERSION}u + include/python${_${_PYTHON_PREFIX}_VERSION} + include + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + + find_path (${_PYTHON_PREFIX}_INCLUDE_DIR + NAMES Python.h + HINTS ${_${_PYTHON_PREFIX}_INCLUDE_HINTS} ${_${_PYTHON_PREFIX}_HINTS} + PATHS ${__${_PYTHON_PREFIX}_FRAMEWORK_PATHS} + ${__${_PYTHON_PREFIX}_REGISTRY_PATHS} + PATH_SUFFIXES include/python${_${_PYTHON_PREFIX}_VERSION}mu + include/python${_${_PYTHON_PREFIX}_VERSION}m + include/python${_${_PYTHON_PREFIX}_VERSION}u + include/python${_${_PYTHON_PREFIX}_VERSION} + include + NO_SYSTEM_ENVIRONMENT_PATH + NO_CMAKE_SYSTEM_PATH) + endif() + + if ((${_PYTHON_PREFIX}_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG) AND ${_PYTHON_PREFIX}_INCLUDE_DIR) + break() + endif() + endforeach() + + # search header file in standard locations + find_path (${_PYTHON_PREFIX}_INCLUDE_DIR + NAMES Python.h) + endif() + + if (${_PYTHON_PREFIX}_INCLUDE_DIR) + # retrieve version from header file + file (STRINGS "${${_PYTHON_PREFIX}_INCLUDE_DIR}/patchlevel.h" _${_PYTHON_PREFIX}_VERSION + REGEX "^#define[ \t]+PY_VERSION[ \t]+\"[^\"]+\"") + string (REGEX REPLACE "^#define[ \t]+PY_VERSION[ \t]+\"([^\"]+)\".*" "\\1" + _${_PYTHON_PREFIX}_VERSION "${_${_PYTHON_PREFIX}_VERSION}") + string (REGEX MATCHALL "[0-9]+" _${_PYTHON_PREFIX}_VERSIONS "${_${_PYTHON_PREFIX}_VERSION}") + list (GET _${_PYTHON_PREFIX}_VERSIONS 0 _${_PYTHON_PREFIX}_VERSION_MAJOR) + list (GET _${_PYTHON_PREFIX}_VERSIONS 1 _${_PYTHON_PREFIX}_VERSION_MINOR) + list (GET _${_PYTHON_PREFIX}_VERSIONS 2 _${_PYTHON_PREFIX}_VERSION_PATCH) + + if (NOT ${_PYTHON_PREFIX}_Interpreter_FOUND AND NOT ${_PYTHON_PREFIX}_Compiler_FOUND) + # set public version information + set (${_PYTHON_PREFIX}_VERSION ${_${_PYTHON_PREFIX}_VERSION}) + set (${_PYTHON_PREFIX}_VERSION_MAJOR ${_${_PYTHON_PREFIX}_VERSION_MAJOR}) + set (${_PYTHON_PREFIX}_VERSION_MINOR ${_${_PYTHON_PREFIX}_VERSION_MINOR}) + set (${_PYTHON_PREFIX}_VERSION_PATCH ${_${_PYTHON_PREFIX}_VERSION_PATCH}) + endif() + endif() + + # define public variables + include (SelectLibraryConfigurations) + select_library_configurations (${_PYTHON_PREFIX}) + if (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE) + set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}") + elseif (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG) + set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}") + else() + set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY "$${_PYTHON_PREFIX}_RUNTIME_LIBRARY-NOTFOUND") + endif() + + _python_set_library_dirs (${_PYTHON_PREFIX}_LIBRARY_DIRS + ${_PYTHON_PREFIX}_LIBRARY_RELEASE ${_PYTHON_PREFIX}_LIBRARY_DEBUG) + if (UNIX) + if (${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$" + OR ${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$") + set (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DIRS ${${_PYTHON_PREFIX}_LIBRARY_DIRS}) + endif() + else() + _python_set_library_dirs (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DIRS + ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG) + endif() + + set (${_PYTHON_PREFIX}_INCLUDE_DIRS "${${_PYTHON_PREFIX}_INCLUDE_DIR}") + + mark_as_advanced (${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE + ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG + ${_PYTHON_PREFIX}_INCLUDE_DIR) + + if ((${_PYTHON_PREFIX}_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG) + AND ${_PYTHON_PREFIX}_INCLUDE_DIR) + if (${_PYTHON_PREFIX}_Interpreter_FOUND OR ${_PYTHON_PREFIX}_Compiler_FOUND) + # development environment must be compatible with interpreter/compiler + if (${_${_PYTHON_PREFIX}_VERSION_MAJOR}.${_${_PYTHON_PREFIX}_VERSION_MINOR} VERSION_EQUAL ${${_PYTHON_PREFIX}_VERSION_MAJOR}.${${_PYTHON_PREFIX}_VERSION_MINOR}) + set (${_PYTHON_PREFIX}_Development_FOUND TRUE) + endif() + elseif (${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) + set (${_PYTHON_PREFIX}_Development_FOUND TRUE) + endif() + endif() + + # Restore the original find library ordering + if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES) + set (CMAKE_FIND_LIBRARY_SUFFIXES ${_${_PYTHON_PREFIX}_CMAKE_FIND_LIBRARY_SUFFIXES}) + endif() +endif() + +# final validation +if (${_PYTHON_PREFIX}_VERSION_MAJOR AND + NOT ${_PYTHON_PREFIX}_VERSION_MAJOR VERSION_EQUAL _${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR) + _python_display_failure ("Could NOT find ${_PYTHON_PREFIX}: Found unsuitable major version \"${${_PYTHON_PREFIX}_VERSION_MAJOR}\", but required major version is exact version \"${_${_PYTHON_PREFIX}_REQUIRED_VERSION_MAJOR}\"") +endif() + +include (FindPackageHandleStandardArgs) +find_package_handle_standard_args (${_PYTHON_PREFIX} + REQUIRED_VARS ${_${_PYTHON_PREFIX}_REQUIRED_VARS} + VERSION_VAR ${_PYTHON_PREFIX}_VERSION + HANDLE_COMPONENTS) + +# Create imported targets and helper functions +if ("Interpreter" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS + AND ${_PYTHON_PREFIX}_Interpreter_FOUND + AND NOT TARGET ${_PYTHON_PREFIX}::Interpreter) + add_executable (${_PYTHON_PREFIX}::Interpreter IMPORTED) + set_property (TARGET ${_PYTHON_PREFIX}::Interpreter + PROPERTY IMPORTED_LOCATION "${${_PYTHON_PREFIX}_EXECUTABLE}") +endif() + +if ("Compiler" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS + AND ${_PYTHON_PREFIX}_Compiler_FOUND + AND NOT TARGET ${_PYTHON_PREFIX}::Compiler) + add_executable (${_PYTHON_PREFIX}::Compiler IMPORTED) + set_property (TARGET ${_PYTHON_PREFIX}::Compiler + PROPERTY IMPORTED_LOCATION "${${_PYTHON_PREFIX}_COMPILER}") +endif() + +if ("Development" IN_LIST ${_PYTHON_PREFIX}_FIND_COMPONENTS + AND ${_PYTHON_PREFIX}_Development_FOUND AND NOT TARGET ${_PYTHON_PREFIX}::Python) + + if (${_PYTHON_PREFIX}_LIBRARY_RELEASE MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$" + OR ${_PYTHON_PREFIX}_LIBRARY_DEBUG MATCHES "${CMAKE_SHARED_LIBRARY_SUFFIX}$" + OR ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE OR ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG) + set (_${_PYTHON_PREFIX}_LIBRARY_TYPE SHARED) + else() + set (_${_PYTHON_PREFIX}_LIBRARY_TYPE STATIC) + endif() + + add_library (${_PYTHON_PREFIX}::Python ${_${_PYTHON_PREFIX}_LIBRARY_TYPE} IMPORTED) + + set_property (TARGET ${_PYTHON_PREFIX}::Python + PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${${_PYTHON_PREFIX}_INCLUDE_DIR}") + + if ((${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE) + OR (${_PYTHON_PREFIX}_LIBRARY_DEBUG AND ${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG)) + # System manage shared libraries in two parts: import and runtime + if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG) + set_property (TARGET ${_PYTHON_PREFIX}::Python PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG) + set_target_properties (${_PYTHON_PREFIX}::Python + PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" + IMPORTED_IMPLIB_RELEASE "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}" + IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_RELEASE}") + set_target_properties (${_PYTHON_PREFIX}::Python + PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" + IMPORTED_IMPLIB_DEBUG "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}" + IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY_DEBUG}") + else() + set_target_properties (${_PYTHON_PREFIX}::Python + PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_IMPLIB "${${_PYTHON_PREFIX}_LIBRARY}" + IMPORTED_LOCATION "${${_PYTHON_PREFIX}_RUNTIME_LIBRARY}") + endif() + else() + if (${_PYTHON_PREFIX}_LIBRARY_RELEASE AND ${_PYTHON_PREFIX}_LIBRARY_DEBUG) + set_property (TARGET ${_PYTHON_PREFIX}::Python PROPERTY IMPORTED_CONFIGURATIONS RELEASE DEBUG) + set_target_properties (${_PYTHON_PREFIX}::Python + PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_RELEASE "C" + IMPORTED_LOCATION_RELEASE "${${_PYTHON_PREFIX}_LIBRARY_RELEASE}") + set_target_properties (${_PYTHON_PREFIX}::Python + PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "C" + IMPORTED_LOCATION_DEBUG "${${_PYTHON_PREFIX}_LIBRARY_DEBUG}") + else() + set_target_properties (${_PYTHON_PREFIX}::Python + PROPERTIES IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${${_PYTHON_PREFIX}_LIBRARY}") + endif() + endif() + + if (_${_PYTHON_PREFIX}_CONFIG AND _${_PYTHON_PREFIX}_LIBRARY_TYPE STREQUAL "STATIC") + # extend link information with dependent libraries + execute_process (COMMAND "${_${_PYTHON_PREFIX}_CONFIG}" --ldflags + RESULT_VARIABLE _${_PYTHON_PREFIX}_RESULT + OUTPUT_VARIABLE _${_PYTHON_PREFIX}_FLAGS + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + if (NOT _${_PYTHON_PREFIX}_RESULT) + string (REGEX MATCHALL "-[Ll][^ ]+" _${_PYTHON_PREFIX}_LINK_LIBRARIES "${_${_PYTHON_PREFIX}_FLAGS}") + # remove elements relative to python library itself + list (FILTER _${_PYTHON_PREFIX}_LINK_LIBRARIES EXCLUDE REGEX "-lpython") + foreach (_${_PYTHON_PREFIX}_DIR IN LISTS ${_PYTHON_PREFIX}_LIBRARY_DIRS) + list (FILTER _${_PYTHON_PREFIX}_LINK_LIBRARIES EXCLUDE REGEX "-L${${_PYTHON_PREFIX}_DIR}") + endforeach() + set_property (TARGET ${_PYTHON_PREFIX}::Python + PROPERTY INTERFACE_LINK_LIBRARIES ${_${_PYTHON_PREFIX}_LINK_LIBRARIES}) + endif() + endif() + + # + # PYTHON_ADD_LIBRARY ( [STATIC|SHARED|MODULE] src1 src2 ... srcN) + # It is used to build modules for python. + # + function (__${_PYTHON_PREFIX}_ADD_LIBRARY prefix name) + cmake_parse_arguments (PARSE_ARGV 2 PYTHON_ADD_LIBRARY + "STATIC;SHARED;MODULE" "" "") + + unset (type) + if (NOT (PYTHON_ADD_LIBRARY_STATIC + OR PYTHON_ADD_LIBRARY_SHARED + OR PYTHON_ADD_LIBRARY_MODULE)) + set (type MODULE) + endif() + add_library (${name} ${type} ${ARGN}) + target_link_libraries (${name} PRIVATE ${prefix}::Python) + + # customize library name to follow module name rules + get_property (type TARGET ${name} PROPERTY TYPE) + if (type STREQUAL "MODULE_LIBRARY") + set_property (TARGET ${name} PROPERTY PREFIX "") + if(CMAKE_SYSTEM_NAME STREQUAL "Windows") + set_property (TARGET ${name} PROPERTY SUFFIX ".pyd") + endif() + endif() + endfunction() +endif() + +# final clean-up + +# Restore CMAKE_FIND_APPBUNDLE +if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE) + set (CMAKE_FIND_APPBUNDLE ${_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE}) + unset (_${_PYTHON_PREFIX}_CMAKE_FIND_APPBUNDLE) +else() + unset (CMAKE_FIND_APPBUNDLE) +endif() +# Restore CMAKE_FIND_FRAMEWORK +if (DEFINED _${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK) + set (CMAKE_FIND_FRAMEWORK ${_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK}) + unset (_${_PYTHON_PREFIX}_CMAKE_FIND_FRAMEWORK) +else() + unset (CMAKE_FIND_FRAMEWORK) +endif() + +unset (_${_PYTHON_PREFIX}_CONFIG CACHE) diff --git a/cmake/FindPython2.cmake b/cmake/FindPython2.cmake new file mode 100644 index 000000000..998e99223 --- /dev/null +++ b/cmake/FindPython2.cmake @@ -0,0 +1,171 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindPython2 +----------- + +Find Python 2 interpreter, compiler and development environment (include +directories and libraries). + +Three components are supported: + +* ``Interpreter``: search for Python 2 interpreter +* ``Compiler``: search for Python 2 compiler. Only offered by IronPython. +* ``Development``: search for development artifacts (include directories and + libraries) + +If no ``COMPONENTS`` is specified, ``Interpreter`` is assumed. + +To ensure consistent versions between components ``Interpreter``, ``Compiler`` +and ``Development``, specify all components at the same time:: + + find_package (Python2 COMPONENTS Interpreter Development) + +This module looks only for version 2 of Python. This module can be used +concurrently with :module:`FindPython3` module to use both Python versions. + +The :module:`FindPython` module can be used if Python version does not matter +for you. + +Imported Targets +^^^^^^^^^^^^^^^^ + +This module defines the following :ref:`Imported Targets `: + +``Python2::Interpreter`` + Python 2 interpreter. Target defined if component ``Interpreter`` is found. +``Python2::Compiler`` + Python 2 compiler. Target defined if component ``Compiler`` is found. +``Python2::Python`` + Python 2 library. Target defined if component ``Development`` is found. + +Result Variables +^^^^^^^^^^^^^^^^ + +This module will set the following variables in your project +(see :ref:`Standard Variable Names `): + +``Python2_FOUND`` + System has the Python 2 requested components. +``Python2_Interpreter_FOUND`` + System has the Python 2 interpreter. +``Python2_EXECUTABLE`` + Path to the Python 2 interpreter. +``Python2_INTERPRETER_ID`` + A short string unique to the interpreter. Possible values include: + * Python + * ActivePython + * Anaconda + * Canopy + * IronPython +``Python2_STDLIB`` + Standard platform independent installation directory. + + Information returned by + ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=True)``. +``Python2_STDARCH`` + Standard platform dependent installation directory. + + Information returned by + ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=True)``. +``Python2_SITELIB`` + Third-party platform independent installation directory. + + Information returned by + ``distutils.sysconfig.get_python_lib(plat_specific=False,standard_lib=False)``. +``Python2_SITEARCH`` + Third-party platform dependent installation directory. + + Information returned by + ``distutils.sysconfig.get_python_lib(plat_specific=True,standard_lib=False)``. +``Python2_Compiler_FOUND`` + System has the Python 2 compiler. +``Python2_COMPILER`` + Path to the Python 2 compiler. Only offered by IronPython. +``Python2_COMPILER_ID`` + A short string unique to the compiler. Possible values include: + * IronPython +``Python2_Development_FOUND`` + System has the Python 2 development artifacts. +``Python2_INCLUDE_DIRS`` + The Python 2 include directories. +``Python2_LIBRARIES`` + The Python 2 libraries. +``Python2_LIBRARY_DIRS`` + The Python 2 library directories. +``Python2_RUNTIME_LIBRARY_DIRS`` + The Python 2 runtime library directories. +``Python2_VERSION`` + Python 2 version. +``Python2_VERSION_MAJOR`` + Python 2 major version. +``Python2_VERSION_MINOR`` + Python 2 minor version. +``Python2_VERSION_PATCH`` + Python 2 patch version. + +Hints +^^^^^ + +``Python2_ROOT_DIR`` + Define the root directory of a Python 2 installation. + +``Python2_USE_STATIC_LIBS`` + * If not defined, search for shared libraries and static libraries in that + order. + * If set to TRUE, search **only** for static libraries. + * If set to FALSE, search **only** for shared libraries. + +``Python2_FIND_REGISTRY`` + On Windows the ``Python2_FIND_REGISTRY`` variable determine the order + of preference between registry and environment variables. + the ``Python2_FIND_REGISTRY`` variable can be set to empty or one of the + following: + + * ``FIRST``: Try to use registry before environment variables. + This is the default. + * ``LAST``: Try to use registry after environment variables. + * ``NEVER``: Never try to use registry. + +``CMAKE_FIND_FRAMEWORK`` + On macOS the :variable:`CMAKE_FIND_FRAMEWORK` variable determine the order of + preference between Apple-style and unix-style package components. + + .. note:: + + Value ``ONLY`` is not supported so ``FIRST`` will be used instead. + +.. note:: + + If a Python virtual environment is configured, set variable + ``Python_FIND_REGISTRY`` (Windows) or ``CMAKE_FIND_FRAMEWORK`` (macOS) with + value ``LAST`` or ``NEVER`` to select it preferably. + +Commands +^^^^^^^^ + +This module defines the command ``Python2_add_library`` which have the same +semantic as :command:`add_library` but take care of Python module naming rules +(only applied if library is of type ``MODULE``) and add dependency to target +``Python2::Python``:: + + Python2_add_library (my_module MODULE src1.cpp) + +If library type is not specified, ``MODULE`` is assumed. +#]=======================================================================] + + +set (_PYTHON_PREFIX Python2) + +set (_Python2_REQUIRED_VERSION_MAJOR 2) + +include (${CMAKE_CURRENT_LIST_DIR}/FindPython/Support.cmake) + +if (COMMAND __Python2_add_library) + macro (Python2_add_library) + __Python2_add_library (Python2 ${ARGV}) + endmacro() +endif() + +unset (_PYTHON_PREFIX) diff --git a/cmake/PrettyCompilerColors.cmake b/cmake/PrettyCompilerColors.cmake new file mode 100644 index 000000000..42f0aeb9b --- /dev/null +++ b/cmake/PrettyCompilerColors.cmake @@ -0,0 +1,21 @@ +include(CheckCCompilerFlag) + +if(CMAKE_C_COMPILER_ID STREQUAL GNU) + unset(COMPILER_COLOR_DIAGNOSTICS) + check_c_compiler_flag(-fdiagnostics-color=always COMPILER_COLOR_DIAGNOSTICS) + if(COMPILER_COLOR_DIAGNOSTICS) + add_compile_options(-fdiagnostics-color=always) + else() + unset(COMPILER_COLOR_DIAGNOSTICS) + check_c_compiler_flag(-fdiagnostics-color COMPILER_COLOR_DIAGNOSTICS) + if(COMPILER_COLOR_DIAGNOSTICS) + add_compile_options(-fdiagnostics-color) + endif() + endif() +elseif(CMAKE_C_COMPILER_ID STREQUAL Clang) + unset(COMPILER_COLOR_DIAGNOSTICS) + check_c_compiler_flag(-fcolor-diagnostics COMPILER_COLOR_DIAGNOSTICS) + if(COMPILER_COLOR_DIAGNOSTICS) + add_compile_options(-fcolor-diagnostics) + endif() +endif() diff --git a/cmake/Set-Toolchain-vcpkg.cmake b/cmake/Set-Toolchain-vcpkg.cmake new file mode 100644 index 000000000..b3abef6b5 --- /dev/null +++ b/cmake/Set-Toolchain-vcpkg.cmake @@ -0,0 +1,56 @@ +if(VCPKG_TARGET_TRIPLET) + if(NOT DEFINED ENV{VCPKG_ROOT}) + get_filename_component(VCPKG_ROOT ${CMAKE_SOURCE_DIR}/../vcpkg ABSOLUTE) + set(ENV{VCPKG_ROOT} ${VCPKG_ROOT}) + else() + set(VCPKG_ROOT $ENV{VCPKG_ROOT}) + endif() + + if(NOT EXISTS ${VCPKG_ROOT}) + get_filename_component(vcpkg_root_parent ${VCPKG_ROOT}/.. ABSOLUTE) + + execute_process( + COMMAND git clone https://github.com/microsoft/vcpkg.git + RESULT_VARIABLE git_status + WORKING_DIRECTORY ${vcpkg_root_parent} + ) + + if(NOT git_status EQUAL 0) + message(FATAL_ERROR "Error cloning vcpkg, please make sure git for windows is installed correctly, it can be installed from Visual Studio components") + endif() + endif() + + # build vcpkg if not built + if(WIN32) + if(NOT EXISTS ${VCPKG_ROOT}/vcpkg.exe) + execute_process( + COMMAND bootstrap-vcpkg.bat + WORKING_DIRECTORY ${VCPKG_ROOT} + ) + endif() + else() + if(NOT EXISTS ${VCPKG_ROOT}/vcpkg) + execute_process( + COMMAND bootstrap-vcpkg.sh + WORKING_DIRECTORY ${VCPKG_ROOT} + ) + endif() + endif() + + foreach(pkg ${VCPKG_DEPS}) + list(APPEND VCPKG_DEPS_QUALIFIED ${pkg}:${VCPKG_TARGET_TRIPLET}) + endforeach() + + # build our deps + execute_process( + COMMAND vcpkg install ${VCPKG_DEPS_QUALIFIED} + WORKING_DIRECTORY ${VCPKG_ROOT} + ) + + if(WIN32 AND VCPKG_TARGET_TRIPLET MATCHES x64) + set(CMAKE_GENERATOR_PLATFORM x64 CACHE STRING "visual studio build architecture" FORCE) + endif() + + set(CMAKE_TOOLCHAIN_FILE ${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake CACHE FILEPATH "vcpkg toolchain" FORCE) + include(${VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake) +endif() diff --git a/cmake/scripts/RewriteArmoryScriptPrefix.cmake b/cmake/scripts/RewriteArmoryScriptPrefix.cmake new file mode 100644 index 000000000..ca4e33630 --- /dev/null +++ b/cmake/scripts/RewriteArmoryScriptPrefix.cmake @@ -0,0 +1,15 @@ +file(READ ${script_file} script_contents) + +string(REGEX REPLACE " /usr" " ${prefix}" script_edited ${script_contents}) + +file(MAKE_DIRECTORY ${script_dir}/script_tmp) + +file(WRITE ${script_dir}/script_tmp/${script_output_file} ${script_edited}) + +file( + COPY ${script_dir}/script_tmp/${script_output_file} + DESTINATION ${script_dir} + FILE_PERMISSIONS OWNER_WRITE OWNER_READ OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE +) + +file(REMOVE ${script_dir}/script_tmp) diff --git a/configure.ac b/configure.ac index 853b2ea7f..2681c1ed2 100644 --- a/configure.ac +++ b/configure.ac @@ -89,7 +89,7 @@ AM_CONDITIONAL([BUILD_GUI], [test x$build_gui = xyes]) AC_PROG_CC AC_PROG_CXX -AM_CONDITIONAL([HAVE_GCC], [test $CXX = g++]) +AM_CONDITIONAL([HAVE_GCC], [$CXX -v 2>&1 | grep -q 'g++']) AC_CHECK_SIZEOF([long unsigned int]) AM_CONDITIONAL([HAVE_64BIT], [test $ac_cv_sizeof_long_unsigned_int = 8]) @@ -279,6 +279,8 @@ if test x$LWS_WITH_TLS_FOUND = xyes; then ]) AC_MSG_RESULT($CRYPTO_LIBDIR) AC_SUBST([CRYPTO_LIBDIR]) + CRYPTO_LDFLAGS=$(pkg-config --libs --static libcrypto 2>/dev/null) + AC_SUBST([CRYPTO_LDFLAGS]) fi AC_MSG_CHECKING(for LWS_WITH_LIBUV) @@ -385,6 +387,7 @@ export LDFLAGS AM_CONDITIONAL([HAVE_CLANG], [test x$CLANG = xyes]) AM_CONDITIONAL([BUILD_DARWIN], [test x$BUILD_OS = xdarwin]) +AM_CONDITIONAL([BUILD_LINUX], [test x$BUILD_OS = xlinux]) AC_CONFIG_FILES(Makefile cppForSwig/Makefile diff --git a/cppForSwig/BlockUtils.h b/cppForSwig/BlockUtils.h index aabf78b06..da77e367c 100644 --- a/cppForSwig/BlockUtils.h +++ b/cppForSwig/BlockUtils.h @@ -48,11 +48,7 @@ #endif #ifdef _MSC_VER - #include "mman.h" - //#include "leveldb_windows_port\win32_posix\win32_posix.h" - #else #include - #include #endif diff --git a/cppForSwig/CMakeLists.txt b/cppForSwig/CMakeLists.txt new file mode 100644 index 000000000..dd180e593 --- /dev/null +++ b/cppForSwig/CMakeLists.txt @@ -0,0 +1,578 @@ +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +add_subdirectory(chacha20poly1305) +add_subdirectory(lmdb/libraries/liblmdb) + +# this is the right way to set options for sub-projects +# we allow these to be overridden by the user +if(NOT DEFINED LIBBTC_WITH_WALLET) + set(LIBBTC_WITH_WALLET OFF CACHE BOOL "disable libbtc wallet" FORCE) +endif() + +if(NOT DEFINED LIBBTC_WITH_NET) + set(LIBBTC_WITH_NET OFF CACHE BOOL "disable libbtc networking" FORCE) +endif() + +if(NOT DEFINED LIBBTC_WITH_TOOLS) + set(LIBBTC_WITH_TOOLS OFF CACHE BOOL "disable libbtc tools" FORCE) +endif() + +if(NOT DEFINED LIBBTC_WITH_TESTS) + set(LIBBTC_WITH_TESTS OFF CACHE BOOL "do not build libbtc tests" FORCE) +endif() + +add_subdirectory(libbtc) + +set(LIBARMORYCOMMON_INCLUDE_DIRECTORIES + PUBLIC lmdb/libraries/liblmdb + PUBLIC . + PRIVATE bech32/ref/c++ + PRIVATE chacha20poly1305 + PRIVATE libbtc/src/secp256k1/include + PRIVATE libbtc/include + PRIVATE ${PROJECT_BINARY_DIR} # for protobuf protoc genned .h files +) + +set(LIBARMORYCOMMON_LINK_LIBRARIES + chacha20poly1305 + btc + lmdb +) + +if(NOT MSVC) + list(APPEND LIBARMORYCOMMON_LINK_LIBRARIES + pthread + ) +endif() + +option(WITH_CRYPTOPP "use Crypto++ crypto functions" OFF) + +unset(LIBARMORYCOMMON_SOURCES) +unset(LIBARMORYCOMMON_COMPILE_DEFINITIONS) + +if(WITH_CRYPTOPP) + add_subdirectory(cryptopp) + + list(APPEND LIBARMORYCOMMON_SOURCES EncryptionUtils.cpp) + + list(APPEND LIBARMORYCOMMON_LINK_LIBRARIES + cryptopp + ) +else() + list(APPEND LIBARMORYCOMMON_COMPILE_DEFINITIONS + PRIVATE LIBBTC_ONLY + ) + + list(APPEND LIBARMORYCOMMON_SOURCES EncryptionUtils_libbtc.cpp) +endif() + +if(CMAKE_TOOLCHAIN_FILE MATCHES vcpkg) + find_package(Libwebsockets CONFIG REQUIRED) + set(LIBWEBSOCKETS_LIBRARIES websockets_shared) +else() + find_package(PkgConfig REQUIRED) + + pkg_check_modules(LIBWEBSOCKETS REQUIRED libwebsockets>=3.0.1) +endif() + +list(APPEND LIBARMORYCOMMON_INCLUDE_DIRECTORIES + PRIVATE ${LIBWEBSOCKETS_INCLUDE_DIRS} +) + +list(APPEND LIBARMORYCOMMON_LINK_LIBRARIES + ${LIBWEBSOCKETS_LIBRARIES} +) + +include(CheckCXXSymbolExists) + +check_cxx_symbol_exists(LWS_WITH_TLS lws_config.h LIBWEBSOCKETS_WITH_TLS) + +if(LIBWEBSOCKETS_WITH_TLS) + if(APPLE) + set(OPENSSL_ROOT_DIR /usr/local/opt/openssl) + endif() + + find_package(OpenSSL REQUIRED) + + list(APPEND LIBARMORYCOMMON_INCLUDE_DIRECTORIES + PUBLIC ${OPENSSL_INCLUDE_DIR} + ) + + list(APPEND LIBARMORYCOMMON_LINK_LIBRARIES + ${OPENSSL_LIBRARIES} + ) +endif() + +check_cxx_symbol_exists(LWS_WITH_LIBUV lws_config.h LIBWEBSOCKETS_WITH_LIBUV) + +if(LIBWEBSOCKETS_WITH_LIBUV) + pkg_check_modules(LIBUV REQUIRED libuv) + + list(APPEND LIBARMORYCOMMON_LINK_LIBRARIES + ${LIBUV_LIBRARIES} + ) +endif() + +check_cxx_symbol_exists(LWS_WITH_LIBEVENT lws_config.h LIBWEBSOCKETS_WITH_LIBEVENT) + +if(LIBWEBSOCKETS_WITH_LIBEVENT) + pkg_check_modules(LIBEVENT REQUIRED libevent) + + list(APPEND LIBARMORYCOMMON_LINK_LIBRARIES + ${LIBEVENT_LIBRARIES} + ) +endif() + +check_cxx_symbol_exists(LWS_WITH_LIBCAP lws_config.h LIBWEBSOCKETS_WITH_LIBCAP) + +if(LIBWEBSOCKETS_WITH_LIBCAP) + pkg_check_modules(LIBCAP REQUIRED libcap) + + list(APPEND LIBARMORYCOMMON_LINK_LIBRARIES + ${LIBCAP_LIBRARIES} + ) +endif() + +if(CMAKE_TOOLCHAIN_FILE MATCHES vcpkg) + find_package(protobuf CONFIG REQUIRED) + set(PROTOBUF_LIBRARIES protobuf::libprotoc protobuf::libprotobuf) +else() + pkg_check_modules(PROTOBUF REQUIRED protobuf>=2.0.0) +endif() + +list(APPEND LIBARMORYCOMMON_INCLUDE_DIRECTORIES + PRIVATE ${PROTOBUF_INCLUDE_DIRS} +) + +list(APPEND LIBARMORYCOMMON_LINK_LIBRARIES + ${PROTOBUF_LIBRARIES} +) + +list(APPEND LIBARMORYCOMMON_SOURCES + Accounts.cpp + Addresses.cpp + AssetEncryption.cpp + Assets.cpp + AsyncClient.cpp + AuthorizedPeers.cpp + BinaryData.cpp + BIP32_Node.cpp + BlockDataManagerConfig.cpp + BtcUtils.cpp + ClientClasses.cpp + CoinSelection.cpp + DecryptedDataContainer.cpp + DerivationScheme.cpp + hkdf.cpp + KDF.cpp + log.cpp + NetworkConfig.cpp + ReentrantLock.cpp + Script.cpp + SecureBinaryData.cpp + ScriptRecipient.cpp + Signer.cpp + SocketObject.cpp + StoredBlockObj.cpp + SwigClient.cpp + Transactions.cpp + TxClasses.cpp + TxEvalState.cpp + txio.cpp + UniversalTimer.cpp + WalletManager.cpp + Wallets.cpp + WebSocketClient.cpp + WebSocketMessage.cpp + DBUtils.cpp + bech32/ref/c++/bech32.cpp + bech32/ref/c++/segwit_addr.cpp +) + +set(PROTOBUF_FILES + AddressBook.proto + AddressData.proto + BDVCommand.proto + CommonTypes.proto + FeeEstimate.proto + LedgerEntry.proto + NodeStatus.proto + Utxo.proto +) + +find_program(PROTOC_EXECUTABLE protoc) + +if(NOT PROTOC_EXECUTABLE) + message(FATAL_ERROR "protocol buffers compiler 'protoc' not found") +endif() + +file(MAKE_DIRECTORY ${PROJECT_BINARY_DIR}/protobuf) + +foreach(proto ${PROTOBUF_FILES}) + string(REGEX REPLACE "\\.proto$" ".pb.cc" proto_cc ${proto}) + + add_custom_command( + OUTPUT ${PROJECT_BINARY_DIR}/protobuf/${proto_cc} + COMMAND ${PROTOC_EXECUTABLE} --cpp_out=${PROJECT_BINARY_DIR}/protobuf --proto_path=${CMAKE_CURRENT_SOURCE_DIR}/protobuf ${CMAKE_CURRENT_SOURCE_DIR}/protobuf/${proto} + DEPENDS protobuf/${proto} + ) + + list(APPEND LIBARMORYCOMMON_SOURCES ${PROJECT_BINARY_DIR}/protobuf/${proto_cc}) +endforeach() + +add_library(ArmoryCommon + STATIC + ${LIBARMORYCOMMON_SOURCES} +) + +target_compile_definitions(ArmoryCommon + PUBLIC __STDC_LIMIT_MACROS + ${LIBARMORYCOMMON_COMPILE_DEFINITIONS} +) + +target_include_directories(ArmoryCommon + ${LIBARMORYCOMMON_INCLUDE_DIRECTORIES} +) + +target_link_libraries(ArmoryCommon + ${LIBARMORYCOMMON_LINK_LIBRARIES} +) + +set(LIBARMORYCLI_SOURCES + BDM_mainthread.cpp + BDM_Server.cpp + BIP150_151.cpp + BitcoinP2P.cpp + Blockchain.cpp + BlockchainScanner.cpp + BlockchainScanner_Super.cpp + BlockDataMap.cpp + BlockDataViewer.cpp + BlockObj.cpp + BlockUtils.cpp + BtcWallet.cpp + DatabaseBuilder.cpp + HistoryPager.cpp + HttpMessage.cpp + JSON_codec.cpp + LedgerEntry.cpp + lmdb_wrapper.cpp + nodeRPC.cpp + Progress.cpp + ScrAddrFilter.cpp + ScrAddrObj.cpp + Server.cpp + SshParser.cpp + StringSockets.cpp + txio.cpp + ZeroConf.cpp +) + +if(MSVC) + list(APPEND LIBARMORYCLI_SOURCES + SocketService_win32.cpp + ) +else() + list(APPEND LIBARMORYCLI_SOURCES + SocketService_unix.cpp + ) +endif() + +add_library(ArmoryCLI + STATIC + ${LIBARMORYCLI_SOURCES} +) + +target_link_libraries(ArmoryCLI + ArmoryCommon +) + +target_compile_definitions(ArmoryCLI + PUBLIC -D__STDC_LIMIT_MACROS +) + +string_option(WITH_GUI "with GUI" AUTO) + +find_package(Qt4 COMPONENTS QtGui QUIET) + +find_program(PYRCC4_EXECUTABLE pyrcc4) +find_program(LRELEASE_EXECUTABLE lrelease) + +if(WITH_GUI STREQUAL AUTO) + if(Qt4_FOUND AND PYRCC4_EXECUTABLE AND LRELEASE_EXECUTABLE) + set(WITH_GUI ON) + else() + set(WITH_GUI OFF) + endif() +endif() + +if(WITH_GUI) + if(NOT PYRCC4_EXECUTABLE) + message(FATAL_ERROR "pyrcc4 not found, install python2-qt4-devel") + endif() + + if(NOT LRELEASE_EXECUTABLE) + message(FATAL_ERROR "lrelease not found, install qt4-linguist") + endif() + + add_library(ArmoryGUI + TransactionBatch.cpp + ) + + target_link_libraries(ArmoryGUI + ArmoryCommon + Qt4::QtGui + ) + + target_compile_definitions(ArmoryGUI + PUBLIC -D__STDC_LIMIT_MACROS + ) +endif() + +add_executable(ArmoryDB + main.cpp +) + +set_target_properties(ArmoryDB + PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR} +) + +target_link_libraries(ArmoryDB + ArmoryCLI +) + +include(GNUInstallDirs) + +install(TARGETS ArmoryDB DESTINATION ${CMAKE_INSTALL_BINDIR}) + +add_executable(BIP150KeyManager + KeyManager.cpp +) + +set_target_properties(BIP150KeyManager + PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR} +) + +target_link_libraries(BIP150KeyManager + ArmoryCLI +) + +install(TARGETS BIP150KeyManager DESTINATION ${CMAKE_INSTALL_BINDIR}) + +string_option(WITH_CLIENT "build python client" AUTO) + +find_package(Python2 COMPONENTS Development QUIET) + +find_program(SWIG_EXECUTABLE swig) + +if(WITH_CLIENT STREQUAL AUTO) + if(Python2_Development_FOUND AND SWIG_EXECUTABLE) + set(WITH_CLIENT ON) + else() + set(WITH_CLIENT OFF) + endif() +endif() + +if(WITH_CLIENT) + if(NOT Python2_Development_FOUND) + message(FATAL_ERROR "python 2 development files not found, install python-dev") + endif() + + if(NOT SWIG_EXECUTABLE) + message(FATAL_ERROR "swig not found") + endif() + + set(CPPBLOCKUTILS_SOURCES + ${PROJECT_BINARY_DIR}/CppBlockUtils_wrap.cxx + ) + + unset(SWIG_OPTS) + + if(CMAKE_COMPILER_IS_GNUCXX) + set(SWIG_OPTS -D__GNUC__) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL Clang) + set(SWIG_OPTS -D__CLANG__) + endif() + + if(CMAKE_C_SIZEOF_DATA_PTR EQUAL 8) # 64 bit + set(SWIG_OPTS ${SWIG_OPTS} -D__LP64__) + endif() + + add_custom_command( + OUTPUT ${PROJECT_BINARY_DIR}/CppBlockUtils_wrap.cxx + COMMAND ${SWIG_EXECUTABLE} -c++ -python -threads ${SWIG_OPTS} -o ${PROJECT_BINARY_DIR}/CppBlockUtils_wrap.cxx ${CMAKE_CURRENT_SOURCE_DIR}/CppBlockUtils.i + DEPENDS CppBlockUtils.i + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + ) + + set(CPPBLOCKUTILS_LINK_LIBRARIES + ArmoryCommon + Python2::Python + ) + + add_library(CppBlockUtils + SHARED + ${CPPBLOCKUTILS_SOURCES} + ) + + set_target_properties(CppBlockUtils + PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR} + ) + + # remove "lib" prefix + set_target_properties(CppBlockUtils + PROPERTIES PREFIX "" + ) + + target_include_directories(CppBlockUtils + PUBLIC Python2::Python + ) + + # copy CppBlockUtils.so to _CppBlockUtils.so as well, why I don't know + add_custom_command( + TARGET CppBlockUtils POST_BUILD + COMMAND ${CMAKE_COMMAND} -E copy + ${PROJECT_BINARY_DIR}/CppBlockUtils${CMAKE_SHARED_LIBRARY_SUFFIX} + ${PROJECT_BINARY_DIR}/_CppBlockUtils${CMAKE_SHARED_LIBRARY_SUFFIX} + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + ) + + if(WITH_GUI) + list(APPEND CPPBLOCKUTILS_LINK_LIBRARIES + ArmoryGUI + ) + + # this mechanism for dependent custom targets I found here: + # https://cmake.org/pipermail/cmake/2010-March/035621.html + add_custom_command( + OUTPUT ${PROJECT_BINARY_DIR}/qrc_img_resources.py + COMMAND ${PYRCC4_EXECUTABLE} -o ${PROJECT_BINARY_DIR}/qrc_img_resources.py ${PROJECT_SOURCE_DIR}/imgList.xml + DEPENDS ${PROJECT_SOURCE_DIR}/imgList.xml + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + ) + + add_custom_target(qrc_img_resources_py DEPENDS ${PROJECT_BINARY_DIR}/qrc_img_resources.py) + + file(COPY ${PROJECT_SOURCE_DIR}/lang DESTINATION ${PROJECT_BINARY_DIR}) + + set(LANG_SOURCES + armory_da.ts + armory_de.ts + armory_el.ts + armory_en.ts + armory_es.ts + armory_fr.ts + armory_he.ts + armory_hr.ts + armory_id.ts + armory_ru.ts + armory_sv.ts + ) + + unset(LANG_QM_FILES) + + foreach(lang_file ${LANG_SOURCES}) + string(REGEX REPLACE "\\.ts$" ".qm" lang_qm_file ${lang_file}) + + add_custom_command( + OUTPUT ${PROJECT_BINARY_DIR}/lang/${lang_qm_file} + COMMAND ${LRELEASE_EXECUTABLE} ${PROJECT_BINARY_DIR}/lang/${lang_file} + WORKING_DIRECTORY ${PROJECT_BINARY_DIR}/lang + ) + + list(APPEND LANG_QM_FILES + ${PROJECT_BINARY_DIR}/lang/${lang_qm_file} + ) + endforeach() + + add_custom_target(lang_lrelease DEPENDS ${LANG_QM_FILES}) + + add_dependencies(CppBlockUtils + qrc_img_resources_py + lang_lrelease + ) + + install(CODE "file(MAKE_DIRECTORY ${CMAKE_INSTALL_LIBDIR}/armory/ui)") + + install(CODE "file(MAKE_DIRECTORY ${CMAKE_INSTALL_LIBDIR}/armory/lang)") + + install(DIRECTORY ../ui DESTINATION ${CMAKE_INSTALL_LIBDIR}/armory) + + install(DIRECTORY ${PROJECT_BINARY_DIR}/lang + DESTINATION ${CMAKE_INSTALL_LIBDIR}/armory + FILES_MATCHING PATTERN "*.qm" + ) + endif() + + target_link_libraries(CppBlockUtils + ${CPPBLOCKUTILS_LINK_LIBRARIES} + ) + + # rewrite prefix for armory script + add_custom_command( + OUTPUT ${PROJECT_BINARY_DIR}/armory + COMMAND ${CMAKE_COMMAND} -Dscript_file=${PROJECT_SOURCE_DIR}/dpkgfiles/armory + -Dscript_output_file=${PROJECT_BINARY_DIR}/armory + -Dscript_dir=${PROJECT_BINARY_DIR} + -Dprefix=${CMAKE_INSTALL_PREFIX} + -P ${PROJECT_SOURCE_DIR}/cmake/scripts/RewriteArmoryScriptPrefix.cmake + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + ) + + add_custom_target(armory_script DEPENDS ${PROJECT_BINARY_DIR}/armory) + + add_dependencies(CppBlockUtils armory_script) + + install(PROGRAMS ${PROJECT_BINARY_DIR}/armory DESTINATION ${CMAKE_INSTALL_BINDIR}) + + install(CODE "file(MAKE_DIRECTORY ${CMAKE_INSTALL_LIBDIR}/armory/armoryengine)") + + install(CODE "file(MAKE_DIRECTORY ${CMAKE_INSTALL_DATAROOTDIR}/applications)") # share/applications + + install( + TARGETS CppBlockUtils + DESTINATION ${CMAKE_INSTALL_LIBDIR}/armory + ) + + # copy the underscore prefixed version too + install( + FILES ${PROJECT_BINARY_DIR}/_CppBlockUtils${CMAKE_SHARED_LIBRARY_SUFFIX} + DESTINATION ${CMAKE_INSTALL_LIBDIR}/armory + ) + + install(FILES + ../armorycolors.py + ../armorymodels.py + ../ArmoryQt.py + ../dynamicImport.py + ../guardian.py + ../jasvet.py + ../LICENSE.py + ../qrcodenative.py + ../qtdefines.py + ../qtdialogs.py + ../SDM.py + ../setup.py + ../subprocess_win.py + ../update_version.py + ../writeNSISCompilerArgs.py + ${PROJECT_BINARY_DIR}/CppBlockUtils.py + ${PROJECT_BINARY_DIR}/qrc_img_resources.py + + DESTINATION ${CMAKE_INSTALL_LIBDIR}/armory + ) + + install(DIRECTORY ../armoryengine DESTINATION ${CMAKE_INSTALL_LIBDIR}/armory) + + install(DIRECTORY ../img + DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/armory + PATTERN ".DS_Store" EXCLUDE + ) +endif() + +option(ENABLE_TESTS "build tests binaries" OFF) + +if(ENABLE_TESTS) + add_subdirectory(gtest) +endif() diff --git a/cppForSwig/Makefile.am b/cppForSwig/Makefile.am index e7cf4443b..158a50b67 100644 --- a/cppForSwig/Makefile.am +++ b/cppForSwig/Makefile.am @@ -103,7 +103,6 @@ ARMORYCLI_SOURCE_FILES = BDM_mainthread.cpp \ BlockUtils.cpp \ BtcWallet.cpp \ DatabaseBuilder.cpp \ - DBUtils.cpp \ HistoryPager.cpp \ HttpMessage.cpp \ JSON_codec.cpp \ @@ -131,6 +130,7 @@ ARMORYCOMMON_SOURCE_FILES = Accounts.cpp \ BtcUtils.cpp \ ClientClasses.cpp \ CoinSelection.cpp \ + DBUtils.cpp \ DecryptedDataContainer.cpp \ DerivationScheme.cpp \ hkdf.cpp \ @@ -250,7 +250,8 @@ ArmoryDB_LDADD = $(LIBARMORYCOMMON) \ $(LIBWEBSOCKETS_STATIC) if BUILD_OPENSSL_SUPPORT ArmoryDB_LDADD += $(LIBSSL_STATIC) \ - $(LIBCRYPTO_STATIC) + $(LIBCRYPTO_STATIC) \ + $(CRYPTO_LDFLAGS) endif if BUILD_LIBUV_SUPPORT ArmoryDB_LDADD += $(LIBUV_STATIC) @@ -299,17 +300,17 @@ libCppBlockUtils_la_CPPFLAGS = $(AM_CPPFLAGS) $(INCLUDE_FILES) \ $(PYTHON_CFLAGS) libCppBlockUtils_la_CXXFLAGS = $(AM_CXXFLAGS) -Ilmdb/libraries/liblmdb \ $(UNIT_TEST_CXXFLAGS) -D__STDC_LIMIT_MACROS -libCppBlockUtils_la_LIBADD = $(LIBARMORYCOMMON) $(LIBCRYPTOPP) \ - -lpthread if BUILD_GUI -libCppBlockUtils_la_LIBADD += $(LIBARMORYGUI) +libCppBlockUtils_la_LIBADD = $(LIBARMORYGUI) $(LIBCRYPTOPP) -lpthread +else +libCppBlockUtils_la_LIBADD = $(LIBARMORYCOMMON) $(LIBCRYPTOPP) -lpthread endif libCppBlockUtils_la_LDFLAGS = $(LDFLAGS) $(LWSLDFLAGS) $(PYTHON_LDFLAGS) -shared BUILT_SOURCES += CppBlockUtils_wrap.cxx #custom rules - always force SWIG to run and compile the resultant C++ file CppBlockUtils_wrap.cxx: CppBlockUtils.i - swig $(SWIG_FLAGS) CppBlockUtils.i + swig $(SWIG_FLAGS) -o CppBlockUtils_wrap.cxx CppBlockUtils.i endif MOSTLYCLEANFILES = $(PROTOBUF_CC) $(PROTOBUF_H) diff --git a/cppForSwig/chacha20poly1305/CMakeLists.txt b/cppForSwig/chacha20poly1305/CMakeLists.txt new file mode 100644 index 000000000..da6178f7c --- /dev/null +++ b/cppForSwig/chacha20poly1305/CMakeLists.txt @@ -0,0 +1,13 @@ +set(CHACHA20POLY1305_SOURCES + poly1305.c + chacha.c + chachapoly_aead.c +) + +add_library(chacha20poly1305 + ${CHACHA20POLY1305_SOURCES} +) + +target_include_directories(chacha20poly1305 + PUBLIC . +) diff --git a/cppForSwig/cryptopp/CMakeLists.txt b/cppForSwig/cryptopp/CMakeLists.txt new file mode 100644 index 000000000..e68ae673d --- /dev/null +++ b/cppForSwig/cryptopp/CMakeLists.txt @@ -0,0 +1,239 @@ +include(ArmorySupport) + +use_cxx11() + +include(CheckIncludeFileCXX) + +set(REQUIRED_HEADERS + arpa/inet.h fcntl.h limits.h netdb.h netinet/in.h stddef.h stdlib.h + string.h sys/ioctl.h sys/socket.h sys/time.h unistd.h +) + +foreach(header ${REQUIRED_HEADERS}) + check_include_file_cxx(${header} ${header}_exists) + + if(NOT ${header}_exists) + message(FATAL_ERROR "required header ${header} not found") + endif() +endforeach() + +include(CheckTypeSize) + +foreach(type size_t ssize_t ptrdiff_t) + check_type_size(${type} ${type}_exists LANGUAGE CXX) + + if(NOT ${type}_exists) + message(FATAL_ERROR "your C++ compiler is missing the required type ${type}") + endif() +endforeach() + +include(CheckFunctionExists) + +set(save_libs ${CMAKE_REQUIRED_LIBRARIES}) + +if(NOT WIN32) + set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} m) # math library +endif() + +foreach(func gethostbyname gettimeofday memmove memset pow select setlocale socket) + check_function_exists(${func} ${func}_exists) + + if(NOT ${func}_exists) + message(FATAL_ERROR "your system is missing the required C library function ${func}") + endif() +endforeach() + +set(CMAKE_REQUIRED_LIBRARIES ${save_libs}) + +set(LIBCRYPTOPP_SOURCES + 3way.cpp + gf2n.cpp + pssr.cpp + socketft.cpp + adler32.cpp + default.cpp + gfpcrypt.cpp + pubkey.cpp + sosemanuk.cpp + algebra.cpp + des.cpp + gost.cpp + queue.cpp + square.cpp + algparam.cpp + dessp.cpp + gzip.cpp + rabin.cpp + squaretb.cpp + arc4.cpp + DetSign.cpp + hex.cpp + randpool.cpp + strciphr.cpp + asn.cpp + dh2.cpp + hmac.cpp + rc2.cpp + tea.cpp + authenc.cpp + dh.cpp + hrtimer.cpp + rc5.cpp + base32.cpp + dll.cpp + ida.cpp + rc6.cpp + tftables.cpp + base64.cpp + idea.cpp + rdtables.cpp + tiger.cpp + basecode.cpp + dsa.cpp + integer.cpp + tigertab.cpp + eax.cpp + iterhash.cpp + rijndael.cpp + trdlocal.cpp + ec2n.cpp + luc.cpp + ripemd.cpp + ttmac.cpp + bfinit.cpp + eccrypto.cpp + md2.cpp + rng.cpp + twofish.cpp + blowfish.cpp + ecp.cpp + md4.cpp + rsa.cpp + blumshub.cpp + elgamal.cpp + md5.cpp + rw.cpp + camellia.cpp + emsa2.cpp + misc.cpp + safer.cpp + cast.cpp + eprecomp.cpp + modes.cpp + salsa.cpp + vmac.cpp + casts.cpp + esign.cpp + mqueue.cpp + seal.cpp + wait.cpp + cbcmac.cpp + files.cpp + mqv.cpp + seed.cpp + wake.cpp + ccm.cpp + filters.cpp + nbtheory.cpp + serpent.cpp + whrlpool.cpp + channels.cpp + fips140.cpp + network.cpp + shacal2.cpp + winpipes.cpp + cmac.cpp + oaep.cpp + sha.cpp + xtr.cpp + cpu.cpp + osrng.cpp + sharkbox.cpp + xtrcrypt.cpp + crc.cpp + gcm.cpp + pch.cpp + shark.cpp + zdeflate.cpp + cryptlib_bds.cpp + gf2_32.cpp + pkcspad.cpp + simple.cpp + zinflate.cpp + cryptlib.cpp + gf256.cpp + polynomi.cpp + skipjack.cpp + zlib.cpp +) + +unset(LIBCRYPTOPP_DEFINITIONS) +unset(LIBCRYPTOPP_COMPILE_OPTIONS) + +option(WITH_HOST_CPU_FEATURES "support the CPU features of the build host" ON) + +if(WITH_HOST_CPU_FEATURES AND CMAKE_CXX_COMPILER_ID STREQUAL GNU) + list(APPEND LIBCRYPTOPP_COMPILE_OPTIONS -march=native) +endif() + +# enable asm on x86, gcc only +if(CMAKE_SYSTEM_PROCESSOR MATCHES "i.86|x86_64" AND CMAKE_CXX_COMPILER_ID STREQUAL GNU) + enable_language(ASM) + + # cmake needs to be patched to support this + execute_process( + COMMAND as --version + COMMAND head -1 + COMMAND awk "{print $NF}" + ERROR_QUIET + OUTPUT_VARIABLE CMAKE_ASM_COMPILER_VERSION + ) + + if(CMAKE_ASM_COMPILER_VERSION VERSION_LESS 2.10) + list(APPEND LIBCRYPTOPP_DEFINITIONS CRYPTOPP_DISABLE_ASM) + elseif(CMAKE_ASM_COMPILER_VERSION VERSION_LESS 2.17) + list(APPEND LIBCRYPTOPP_DEFINITIONS CRYPTOPP_DISABLE_SSE3) + endif() + + if(WITH_HOST_CPU_FEATURES AND CMAKE_SYSTEM_NAME STREQUAL Linux) + execute_process(COMMAND grep -o -m 1 aes /proc/cpuinfo OUTPUT_VARIABLE HAVE_AES) + execute_process(COMMAND grep -o -m 1 pclmul /proc/cpuinfo OUTPUT_VARIABLE HAVE_PCLMUL) + + if(HAVE_AES) + list(APPEND LIBCRYPTOPP_COMPILE_OPTIONS -maes) + list(APPEND LIBCRYPTOPP_DEFINITIONS CRYPTOPP_ENABLE_AESNI) + endif() + + if(HAVE_PCLMUL) + list(APPEND LIBCRYPTOPP_COMPILE_OPTIONS -mpclmul) + endif() + endif() + + check_x86_cpu_features() + + list(APPEND LIBCRYPTOPP_COMPILE_OPTIONS ${X86_CPU_FEATURES_COMPILER_FLAGS}) +else() + list(APPEND LIBCRYPTOPP_DEFINITIONS CRYPTOPP_DISABLE_ASM) +endif() + +add_library(cryptopp + ${LIBCRYPTOPP_SOURCES} +) + +if(LIBCRYPTOPP_DEFINITIONS) + target_compile_definitions(cryptopp + PRIVATE ${LIBCRYPTOPP_DEFINITIONS} + ) +endif() + +if(LIBCRYPTOPP_COMPILE_OPTIONS) + target_compile_options(cryptopp + PRIVATE ${LIBCRYPTOPP_COMPILE_OPTIONS} + ) +endif() + +if(NOT WIN32) + target_link_libraries(cryptopp + m # math + ) +endif() diff --git a/cppForSwig/gtest/CMakeLists.txt b/cppForSwig/gtest/CMakeLists.txt new file mode 100644 index 000000000..3c5d7541f --- /dev/null +++ b/cppForSwig/gtest/CMakeLists.txt @@ -0,0 +1,81 @@ +set(GTEST_COMPILE_DEFINITIONS + PUBLIC -DUNIT_TESTS +) + +if(APPLE) + list(APPEND GTEST_COMPILE_DEFINITIONS + PRIVATE -DGTEST_USE_OWN_TR1_TUPLE=1 + ) +endif() + +file(COPY input_files DESTINATION ${PROJECT_BINARY_DIR}) + +add_library(gtest + TestUtils.cpp + NodeUnitTest.cpp + gtest-all.cc +) + +target_link_libraries(gtest + ArmoryCLI +) + +add_executable(ContainerTests + ContainerTests.cpp +) + +target_link_libraries(ContainerTests + gtest +) + +set_target_properties(ContainerTests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + +add_executable(BIP151RekeyTest + BIP151RekeyTest.cpp +) + +target_link_libraries(BIP151RekeyTest + gtest +) + +set_target_properties(BIP151RekeyTest PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + +add_executable(SupernodeTests + SupernodeTests.cpp +) + +target_link_libraries(SupernodeTests + gtest +) + +set_target_properties(SupernodeTests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + +add_executable(CppBlockUtilsTests + CppBlockUtilsTests.cpp +) + +target_link_libraries(CppBlockUtilsTests + gtest +) + +set_target_properties(CppBlockUtilsTests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + +add_executable(WalletTests + WalletTests.cpp +) + +target_link_libraries(WalletTests + gtest +) + +set_target_properties(WalletTests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + +add_executable(SignerTests + SignerTests.cpp +) + +target_link_libraries(SignerTests + gtest +) + +set_target_properties(SignerTests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) diff --git a/cppForSwig/libbtc/CMakeLists.txt b/cppForSwig/libbtc/CMakeLists.txt new file mode 100644 index 000000000..742320401 --- /dev/null +++ b/cppForSwig/libbtc/CMakeLists.txt @@ -0,0 +1,242 @@ +# this is the right way to set options for sub-projects +set(SECP256K1_MODULE_RECOVERY ON CACHE BOOL "enable sec256k1 recovery module" FORCE) + +add_subdirectory(src/secp256k1) + +set(LIBBTC_SOURCES + src/aes256_cbc.c + src/base58.c + src/bip32.c + src/block.c + src/buffer.c + src/chainparams.c + src/commontools.c + src/cstr.c + src/ctaes.c + src/ecc_key.c + src/ecc_libsecp256k1.c + src/memory.c + src/random.c + src/ripemd160.c + src/script.c + src/segwit_addr.c + src/serialize.c + src/sha2.c + src/tx.c + src/utils.c + src/vector.c +) + +include(CheckIncludeFile) + +check_include_file("dlfcn.h" HAVE_DLFCN_H) +check_include_file("inttypes.h" HAVE_INTTYPES_H) +check_include_file("memory.h" HAVE_MEMORY_H) +check_include_file("stdbool.h" HAVE_STDBOOL_H) +check_include_file("stdint.h" HAVE_STDINT_H) +check_include_file("stdlib.h" HAVE_STDLIB_H) +check_include_file("strings.h" HAVE_STRINGS_H) +check_include_file("string.h" HAVE_STRING_H) +check_include_file("sys/stat.h" HAVE_SYS_STAT_H) +check_include_file("sys/types.h" HAVE_SYS_TYPES_H) +check_include_file("unistd.h" HAVE_UNISTD_H) + +option(LIBBTC_WITH_WALLET "with libbtc wallet/database functions" ON) + +set(WITH_WALLET ${LIBBTC_WITH_WALLET}) + +if(LIBBTC_WITH_WALLET) + list(APPEND LIBBTC_SOURCES + src/logdb/logdb_core.c + src/logdb/logdb_memdb_llist.c + src/logdb/logdb_memdb_rbtree.c + src/logdb/logdb_rec.c + src/logdb/red_black_tree.c + src/wallet.c + ) +endif() + +option(LIBBTC_WITH_NET "with libbtc networking" ON) + +set(WITH_NET ${LIBBTC_WITH_NET}) + +set(LIBBTC_LINK_LIBRARIES + secp256k1 +) + +# these have to be PUBLIC for the tools targets +set(LIBBTC_INCLUDE_DIRECTORIES + PUBLIC include + PUBLIC src/logdb/include + PUBLIC ${PROJECT_BINARY_DIR} # for config.h +) + +if(LIBBTC_WITH_NET) + find_package(PkgConfig REQUIRED) + + pkg_check_modules(LIBEVENT REQUIRED libevent) + pkg_check_modules(LIBEVENT_PTHREADS REQUIRED libevent_pthreads) + + list(APPEND LIBBTC_LINK_LIBRARIES + ${LIBEVENT_LIBRARIES} + ${LIBEVENT_PTHREADS_LIBRARIES} + ) + + list(APPEND LIBBTC_INCLUDE_DIRECTORIES + PRIVATE ${LIBEVENT_INCLUDE_DIRS} + PRIVATE ${LIBEVENT_PTHREADS_INCLUDE_DIRS} + ) + + list(APPEND LIBBTC_SOURCES + src/headersdb_file.c + src/net.c + src/netspv.c + src/protocol.c + ) +endif() + +option(LIBBTC_WITH_TESTS "with libbtc tests" ON) + +option(LIBBTC_WITH_TOOLS "with libbtc tool cli applications" ON) + +include(CheckCXXSourceCompiles) + +check_cxx_source_compiles(" + void myfunc() + { + __builtin_expect(0,0); + } +" HAVE_BUILTIN_EXPECT) + +string_option(LIBBTC_RANDOM_DEVICE "device to use for random numbers, generally /dev/urandom on linux" /dev/urandom) + +set(RANDOM_DEVICE ${LIBBTC_RANDOM_DEVICE}) + +if(RANDOM_DEVICE STREQUAL /dev/urandom OR RANDOM_DEVICE STREQUAL /dev/random) + set(FILE_RANDOM TRUE) +endif() + +set(PACKAGE_NAME libbtc) + +set(LIBBTC_VERSION 0.1) + +set(PACKAGE_VERSION ${LIBBTC_VERSION}) + +configure_file( + src/libbtc-config.h.cmakein + ${PROJECT_BINARY_DIR}/libbtc-config.h +) + +add_library(btc + ${LIBBTC_SOURCES} +) + +target_include_directories(btc + ${LIBBTC_INCLUDE_DIRECTORIES} +) + +target_link_libraries(btc + ${LIBBTC_LINK_LIBRARIES} +) + +target_compile_definitions(btc + PUBLIC HAVE_CONFIG_H +) + +if(LIBBTC_WITH_TOOLS) + add_executable(bitcointool + src/tools/bitcointool.c + ) + + set_target_properties(bitcointool PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + + target_link_libraries(bitcointool btc) + + if(LIBBTC_WITH_NET) + add_executable(bitcoin-send-tx + src/tools/bitcoin-send-tx.c + ) + + set_target_properties(bitcoin-send-tx PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + + target_link_libraries(bitcoin-send-tx btc) + + add_executable(bitcoin-spv + src/tools/bitcoin-spv.c + ) + + set_target_properties(bitcoin-spv PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) + + target_link_libraries(bitcoin-spv btc) + endif() +endif() + +# we don't need this but upstream might +if(FALSE) + configure_file( + libbtc.pc.cmakein + ${CMAKE_CURRENT_BINARY_DIR}/libbtc.pc @ONLY + ) + + include(GNUInstallDirs) + + install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/libbtc.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig + ) +endif() + +if(LIBBTC_WITH_TESTS) + set(TESTS_SOURCES + test/aes_tests.c + test/base58check_tests.c + test/bip32_tests.c + test/block_tests.c + test/buffer_tests.c + test/cstr_tests.c + test/ecc_tests.c + test/eckey_tests.c + test/hash_tests.c + test/memory_tests.c + test/random_tests.c + test/serialize_tests.c + test/sha2_tests.c + test/utest.h + test/unittester.c + test/tx_tests.c + test/utils_tests.c + test/vector_tests.c + ) + + if(LIBBTC_WITH_WALLET) + list(APPEND TESTS_SOURCES + test/wallet_tests.c + src/logdb/test/logdb_tests.c + src/logdb/test/tests_red_black_tree.c + ) + endif() + + if(LIBBTC_WITH_NET) + list(APPEND TESTS_SOURCES + test/net_tests.c + test/netspv_tests.c + test/protocol_tests.c + ) + endif() + + if(LIBBTC_WITH_TOOLS) + list(APPEND TESTS_SOURCES + test/tool_tests.c + ) + endif() + + add_executable(libbtc-tests + ${TESTS_SOURCES} + ) + + target_link_libraries(libbtc-tests + btc + ) + + set_target_properties(libbtc-tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}) +endif() diff --git a/cppForSwig/libbtc/Makefile.am b/cppForSwig/libbtc/Makefile.am index 6e22fc834..a550ba4a0 100644 --- a/cppForSwig/libbtc/Makefile.am +++ b/cppForSwig/libbtc/Makefile.am @@ -62,7 +62,7 @@ libbtc_la_SOURCES = \ src/utils.c \ src/vector.c -libbtc_la_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/logdb/include +libbtc_la_CFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/logdb/include -I$(top_srcdir)/src/secp256k1/src libbtc_la_LIBADD = $(LIBSECP256K1) if USE_TESTS diff --git a/cppForSwig/libbtc/libbtc.pc.cmakein b/cppForSwig/libbtc/libbtc.pc.cmakein new file mode 100644 index 000000000..d74760c6f --- /dev/null +++ b/cppForSwig/libbtc/libbtc.pc.cmakein @@ -0,0 +1,12 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@CMAKE_INSTALL_LIBDIR@ +includedir=@CMAKE_INSTALL_INCLUDEDIR@ + +Name: libbtc +Description: C library for manipulating bitcoin data structures +URL: https://github.com/jonasschnelli/libbtc +Version: @LIBBTC_VERSION@ +Cflags: -I${includedir} +Libs: -L${libdir} -lbtc + diff --git a/cppForSwig/libbtc/src/libbtc-config.h.cmakein b/cppForSwig/libbtc/src/libbtc-config.h.cmakein new file mode 100644 index 000000000..ae4e6c32e --- /dev/null +++ b/cppForSwig/libbtc/src/libbtc-config.h.cmakein @@ -0,0 +1,59 @@ +#ifndef LIBBTC_CONFIG_H + +#define LIBBTC_CONFIG_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MEMORY_H + +/* Define to 1 if stdbool.h conforms to C99. */ +#cmakedefine HAVE_STDBOOL_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H + +/* Define this symbol if __builtin_expect is available */ +#cmakedefine HAVE_BUILTIN_EXPECT + +/* Define to set random file handle */ +#define RANDOM_DEVICE "@RANDOM_DEVICE@" + +/* Define to 1 to enable /dev/random or /dev/urandom as random device */ +#cmakedefine FILE_RANDOM + +/* Define to 1 to enable net compilation */ +#cmakedefine WITH_NET + +/* Define to 1 to enable wallet compilation */ +#cmakedefine WITH_WALLET + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "@PACKAGE_NAME@" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "@PACKAGE_VERSION@" + +#endif /*LIBBTC_CONFIG_H*/ diff --git a/cppForSwig/libbtc/src/secp256k1/CMakeLists.txt b/cppForSwig/libbtc/src/secp256k1/CMakeLists.txt new file mode 100644 index 000000000..e7a3ada79 --- /dev/null +++ b/cppForSwig/libbtc/src/secp256k1/CMakeLists.txt @@ -0,0 +1,213 @@ +set(SECP256K1_VERSION 0.1) # I have no idea actually, this is not used + +set(SECP256K1_SOURCES + src/secp256k1.c +) + +option(SECP256K1_ENABLE_ASM "enable asm for secp256k1" ON) + +unset(USE_ASM_X86_64) +unset(USE_EXTERNAL_ASM) + +if(SECP256K1_ENABLE_ASM) + if(CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64) + set(USE_ASM_X86_64 ON) + elseif(CMAKE_SYSTEM_PROCESSOR MATCHES arm) + set(USE_EXTERNAL_ASM ON) + list(APPEND SECP256K1_SOURCES src/asm/field_10x26_arm.s) + endif() +endif() + +add_library(secp256k1 + ${SECP256K1_SOURCES} +) + +target_compile_definitions(secp256k1 + PRIVATE SECP256K1_BUILD HAVE_CONFIG_H +) + +# make the config file + +include(CheckIncludeFile) + +check_include_file("inttypes.h" HAVE_INTTYPES_H) +check_include_file("memory.h" HAVE_MEMORY_H) +check_include_file("stdint.h" HAVE_STDINT_H) +check_include_file("stdlib.h" HAVE_STDLIB_H) +check_include_file("strings.h" HAVE_STRINGS_H) +check_include_file("string.h" HAVE_STRING_H) +check_include_file("sys/stat.h" HAVE_SYS_STAT_H) +check_include_file("sys/types.h" HAVE_SYS_TYPES_H) +check_include_file("unistd.h" HAVE_UNISTD_H) + +include(TestBigEndian) + +test_big_endian(WORDS_BIGENDIAN) + +include(CheckTypeSize) + +check_type_size(__int128 HAVE___INT128) + +check_type_size(uint128_t HAVE_UINT128_T) + +string_option(SECP256K1_USE_LIBGMP "use libgmp for secp256k1" AUTO) + +unset(LIBGMP_REQUIRED) +unset(HAVE_LIBGMP) + +if(SECP256K1_USE_LIBGMP AND (NOT SECP256K1_USE_LIBGMP STREQUAL AUTO)) + set(LIBGMP_REQUIRED REQUIRED) +elseif(NOT SECP256K1_USE_LIBGMP) + set(HAVE_LIBGMP NO) +endif() + +unset(USE_NUM_NONE) +unset(USE_NUM_GMP) +unset(USE_FIELD_INV_BUILTIN) +unset(USE_FIELD_INV_NUM) +unset(USE_SCALAR_INV_BUILTIN) +unset(USE_SCALAR_INV_NUM) + +if(NOT DEFINED HAVE_LIBGMP) + find_library(GMP_LIBRARIES NAMES gmp ${LIBGMP_REQUIRED}) + + if(GMP_LIBRARIES) + set(HAVE_LIBGMP ON) + + target_link_libraries(secp256k1 + ${GMP_LIBRARIES} + ) + + set(USE_NUM_GMP ON) + set(USE_FIELD_INV_NUM ON) + set(USE_SCALAR_INV_NUM ON) + else() + set(HAVE_LIBGMP OFF) + endif() +endif() + +if(NOT HAVE_LIBGMP) + set(USE_NUM_NONE ON) + set(USE_FIELD_INV_BUILTIN ON) + set(USE_SCALAR_INV_BUILTIN ON) +endif() + +option(SECP256K1_MODULE_ECDH "enable ecdh module for secp256k1" OFF) + +unset(ENABLE_MODULE_ECDH) + +if(SECP256K1_MODULE_ECDH) + set(ENABLE_MODULE_ECDH ON) +endif() + +option(SECP256K1_MODULE_RECOVERY "enable recovery module for secp256k1" OFF) + +unset(ENABLE_MODULE_RECOVERY) + +if(SECP256K1_MODULE_RECOVERY) + set(ENABLE_MODULE_RECOVERY ON) +endif() + +option(SECP256K1_MODULE_SCHNORR "enable schnorr module for secp256k1" OFF) + +unset(ENABLE_MODULE_SCHNORR) + +if(SECP256K1_MODULE_SCHNORR) + set(ENABLE_MODULE_SCHNORR ON) +endif() + +option(SECP256K1_ECMULT_STATIC_PRECOMPUTATION "use a statically generated ecmult table for secp256k1" OFF) + +unset(USE_ECMULT_STATIC_PRECOMPUTATION) + +if(SECP256K1_ECMULT_STATIC_PRECOMPUTATION) + set(USE_ECMULT_STATIC_PRECOMPUTATION ON) +endif() + +option(SECP256K1_ENDOMORPHISM "use endomorphism optimization for secp256k1" OFF) + +unset(USE_ENDOMORPHISM) + +if(SECP256K1_ENDOMORPHISM) + set(USE_ENDOMORPHISM ON) +endif() + +string_option(SECP256K1_WITH_FIELD "use '32bit', '64bit' or 'AUTO' field with secp256k1" AUTO) + +string_option(SECP256K1_WITH_SCALAR "use '32bit', '64bit' or 'AUTO' scalar with secp256k1" AUTO) + +if(SECP256K1_WITH_FIELD STREQUAL AUTO) + set(SECP256K1_WITH_FIELD 32bit) + + # 64 bit + if(CMAKE_C_SIZEOF_DATA_PTR EQUAL 8 AND (HAVE_LIBGMP OR HAVE_UINT128_T)) + set(SECP256K1_WITH_FIELD 64bit) + endif() +endif() + +if(SECP256K1_WITH_FIELD STREQUAL 64bit AND (NOT (HAVE_LIBGMP OR HAVE_UINT128_T))) + message(FATAL_ERROR "64bit field support requires your compiler to have the 'uint128_t' type when not using libgmp") +endif() + +if(SECP256K1_WITH_SCALAR STREQUAL AUTO) + set(SECP256K1_WITH_SCALAR 32bit) + + # 64 bit + if(CMAKE_C_SIZEOF_DATA_PTR EQUAL 8 AND (HAVE_LIBGMP OR HAVE_UINT128_T)) + set(SECP256K1_WITH_SCALAR 64bit) + endif() +endif() + +if(SECP256K1_WITH_SCALAR STREQUAL 64bit AND (NOT (HAVE_LIBGMP OR HAVE_UINT128_T))) + message(FATAL_ERROR "64bit scalar support requires your compiler to have the 'uint128_t' type when not using libgmp") +endif() + +unset(USE_FIELD_5X52) +unset(USE_FIELD_10X26) + +if(SECP256K1_WITH_FIELD STREQUAL 64bit) + set(USE_FIELD_5X52 ON) +elseif(SECP256K1_WITH_FIELD STREQUAL 32bit) + set(USE_FIELD_10X26 ON) +else() + message(FATAL_ERROR "invalid value for SECP256K1_WITH_FIELD, must be '64bit', '32bit' or 'AUTO'") +endif() + +unset(USE_SCALAR_4X64) +unset(USE_SCALAR_8X32) + +if(SECP256K1_WITH_SCALAR STREQUAL 64bit) + set(USE_SCALAR_4X64 ON) +elseif(SECP256K1_WITH_SCALAR STREQUAL 32bit) + set(USE_SCALAR_8X32 ON) +else() + message(FATAL_ERROR "invalid value for SECP256K1_WITH_SCALAR, must be '64bit', '32bit' or 'AUTO'") +endif() + +configure_file( + src/libsecp256k1-config.h.cmakein + ${PROJECT_BINARY_DIR}/libsecp256k1-config.h +) + +# we don't need this but upstream might +if(FALSE) + configure_file( + libsecp256k1.pc.cmakein + ${CMAKE_CURRENT_BINARY_DIR}/libsecp256k1.pc @ONLY + ) + + include(GNUInstallDirs) + + install( + FILES ${CMAKE_CURRENT_BINARY_DIR}/libsecp256k1.pc + DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig + ) +endif() + +target_include_directories(secp256k1 + PUBLIC include + PRIVATE . + PRIVATE ../../include + PRIVATE ../../src + PRIVATE ${PROJECT_BINARY_DIR} +) diff --git a/cppForSwig/libbtc/src/secp256k1/Makefile.am b/cppForSwig/libbtc/src/secp256k1/Makefile.am index 3d130bdcb..aa1b38935 100644 --- a/cppForSwig/libbtc/src/secp256k1/Makefile.am +++ b/cppForSwig/libbtc/src/secp256k1/Makefile.am @@ -69,7 +69,7 @@ endif endif libsecp256k1_la_SOURCES = src/secp256k1.c -libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(top_srcdir)/include -I$(top_srcdir)/src $(SECP_INCLUDES) +libsecp256k1_la_CPPFLAGS = -DSECP256K1_BUILD -I$(abs_builddir)/include -I$(abs_builddir)/src $(SECP_INCLUDES) libsecp256k1_la_LIBADD = $(JNI_LIB) $(SECP_LIBS) $(COMMON_LIB) libsecp256k1_jni_la_SOURCES = src/java/org_bitcoin_NativeSecp256k1.c src/java/org_bitcoin_Secp256k1Context.c diff --git a/cppForSwig/libbtc/src/secp256k1/include/secp256k1.h b/cppForSwig/libbtc/src/secp256k1/include/secp256k1.h index 7145dbcc5..eb2a52c64 100644 --- a/cppForSwig/libbtc/src/secp256k1/include/secp256k1.h +++ b/cppForSwig/libbtc/src/secp256k1/include/secp256k1.h @@ -7,6 +7,10 @@ extern "C" { #include +#ifdef HAVE_CONFIG_H +#include "libsecp256k1-config.h" +#endif + /* These rules specify the order of arguments in API calls: * * 1. Context pointers go first, followed by output arguments, combined diff --git a/cppForSwig/libbtc/src/secp256k1/libsecp256k1.pc.cmakein b/cppForSwig/libbtc/src/secp256k1/libsecp256k1.pc.cmakein new file mode 100644 index 000000000..828bc2584 --- /dev/null +++ b/cppForSwig/libbtc/src/secp256k1/libsecp256k1.pc.cmakein @@ -0,0 +1,13 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +exec_prefix=@CMAKE_INSTALL_PREFIX@ +libdir=@CMAKE_INSTALL_LIBDIR@ +includedir=@CMAKE_INSTALL_INCLUDEDIR@ + +Name: libsecp256k1 +Description: Optimized C library for EC operations on curve secp256k1 +URL: https://github.com/bitcoin-core/secp256k1 +Version: @SECP256K1_VERSION@ +Cflags: -I${includedir} +Libs.private: @LIBSECP256K1_LIBS@ +Libs: -L${libdir} -lsecp256k1 + diff --git a/cppForSwig/libbtc/src/secp256k1/src/libsecp256k1-config.h.cmakein b/cppForSwig/libbtc/src/secp256k1/src/libsecp256k1-config.h.cmakein new file mode 100644 index 000000000..015e204d2 --- /dev/null +++ b/cppForSwig/libbtc/src/secp256k1/src/libsecp256k1-config.h.cmakein @@ -0,0 +1,106 @@ +#ifndef LIBSECP256K1_CONFIG_H + +#define LIBSECP256K1_CONFIG_H + +/* Define this symbol to enable the ECDH module */ +#cmakedefine ENABLE_MODULE_ECDH + +/* Define this symbol to enable the ECDSA pubkey recovery module */ +#cmakedefine ENABLE_MODULE_RECOVERY + +/* Define this symbol to enable the Schnorr signature module */ +#cmakedefine ENABLE_MODULE_SCHNORR + +/* Define this symbol if OpenSSL EC functions are available */ +#cmakedefine ENABLE_OPENSSL_TESTS + +/* Define this symbol if __builtin_expect is available */ +#cmakedefine HAVE_BUILTIN_EXPECT + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_DLFCN_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_INTTYPES_H + +/* Define this symbol if libcrypto is installed */ +#cmakedefine HAVE_LIBCRYPTO + +/* Define this symbol if libgmp is installed */ +#cmakedefine HAVE_LIBGMP + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_MEMORY_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_STRING_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#cmakedefine HAVE_UNISTD_H + +/* Define to 1 if the system has the type `__int128'. */ +#cmakedefine HAVE___INT128 + +/* Define this symbol to enable x86_64 assembly optimizations */ +#cmakedefine USE_ASM_X86_64 + +/* Define this symbol to use a statically generated ecmult table */ +#cmakedefine USE_ECMULT_STATIC_PRECOMPUTATION + +/* Define this symbol to use endomorphism optimization */ +#cmakedefine USE_ENDOMORPHISM + +/* Define this symbol if an external (non-inline) assembly implementation is + used */ +#cmakedefine USE_EXTERNAL_ASM + +/* Define this symbol to use the FIELD_10X26 implementation */ +#cmakedefine USE_FIELD_10X26 + +/* Define this symbol to use the FIELD_5X52 implementation */ +#cmakedefine USE_FIELD_5X52 + +/* Define this symbol to use the native field inverse implementation */ +#cmakedefine USE_FIELD_INV_BUILTIN + +/* Define this symbol to use the num-based field inverse implementation */ +#cmakedefine USE_FIELD_INV_NUM + +/* Define this symbol to use the gmp implementation for num */ +#cmakedefine USE_NUM_GMP + +/* Define this symbol to use no num implementation */ +#cmakedefine USE_NUM_NONE + +/* Define this symbol to use the 4x64 scalar implementation */ +#cmakedefine USE_SCALAR_4X64 + +/* Define this symbol to use the 8x32 scalar implementation */ +#cmakedefine USE_SCALAR_8X32 + +/* Define this symbol to use the native scalar inverse implementation */ +#cmakedefine USE_SCALAR_INV_BUILTIN + +/* Define this symbol to use the num-based scalar inverse implementation */ +#cmakedefine USE_SCALAR_INV_NUM + +/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most + significant byte first (like Motorola and SPARC, unlike Intel). */ +#cmakedefine WORDS_BIGENDIAN + +#endif /*LIBSECP256K1_CONFIG_H*/ diff --git a/cppForSwig/lmdb/libraries/liblmdb/CMakeLists.txt b/cppForSwig/lmdb/libraries/liblmdb/CMakeLists.txt new file mode 100644 index 000000000..a30c8f662 --- /dev/null +++ b/cppForSwig/lmdb/libraries/liblmdb/CMakeLists.txt @@ -0,0 +1,37 @@ +set(LMDB_SOURCES + lmdbpp.cpp + mdb.c + midl.c +) + +set(LMDB_INCLUDE_DIRECTORIES + PRIVATE lmdb/libraries/liblmdb +) + +if(MSVC) + list(APPEND LMDB_SOURCES + ../../../leveldb_windows_port/win32_posix/dirent_win32.cpp + ../../../leveldb_windows_port/win32_posix/mman.cpp + ../../../leveldb_windows_port/win32_posix/pthread_win32port.cpp + ../../../leveldb_windows_port/win32_posix/Win_TranslatePath.cpp + ../../../leveldb_windows_port/win32_posix/win32_posix.cc + ) + + list(APPEND LMDB_INCLUDE_DIRECTORIES + PUBLIC ../../../leveldb_windows_port/win32_posix + ) +endif() + +add_library(lmdb + ${LMDB_SOURCES} +) + +target_include_directories(lmdb + ${LMDB_INCLUDE_DIRECTORIES} +) + +if(APPLE) + target_compile_definitions(lmdb + PRIVATE MDB_USE_POSIX_SEM=1 + ) +endif()