diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ac9a159d..3adbb0c79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,16 @@ -cmake_minimum_required(VERSION 3.8) -project(libtorrent) +cmake_minimum_required(VERSION 3.10.0 FATAL_ERROR) + +project(libtorrent + DESCRIPTION "Bittorrent library" + VERSION 1.1.10 +) + set (SOVERSION "9") -set (VERSION "1.1.10") + +list(APPEND CMAKE_MODULE_PATH ${libtorrent_SOURCE_DIR}/cmake/Modules) +include(FeatureSummary) +include(GNUInstallDirs) +include(GeneratePkgConfig) set(sources web_connection_base @@ -156,102 +165,155 @@ set(ed25519_sources set(includes include ed25519/src) -option(shared "build libtorrent as a shared library" ON) -option(static_runtime "build libtorrent with static runtime" OFF) -option(tcmalloc "link against google performance tools tcmalloc" OFF) -option(pool-allocators "Uses a pool allocator for disk and piece buffers" ON) -option(encryption "link against openssl and enable encryption" ON) -option(dht "enable support for Mainline DHT" ON) -option(resolve-countries "enable support for resolving countries from peer IPs" ON) -option(unicode "enable unicode support" ON) -option(deprecated-functions "enable deprecated functions for backwards compatibility" ON) -option(exceptions "build with exception support" ON) -option(logging "build with logging" ON) -option(build_tests "build tests" OFF) +function(list_prepend _listName _prefix) + string(REGEX REPLACE "([^;]+)" "${_prefix}\\1" _tmp_list "${${_listName}}") + set (${_listName} "${_tmp_list}" PARENT_SCOPE) +endfunction() -set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo) +list_prepend(sources "src/") +list_prepend(kademlia_sources "src/kademlia/") +list_prepend(ed25519_sources "ed25519/src/") -if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release FORCE) -endif() - -# add_definitions() doesn't seem to let you say wich build type to apply it to -set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DTORRENT_DEBUG") -if(UNIX) - set(CMAKE_C_FLAGS_RELWITHDEBINFO "-Os -g") - set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO}") -endif() - -find_package(Threads REQUIRED) - -include_directories(${includes}) - -if (encryption) - list(APPEND sources mpi pe_crypto) - if(NOT DEFINED OPENSSL_INCLUDE_DIR OR NOT DEFINED OPENSSL_LIBRARIES) - FIND_PACKAGE(OpenSSL REQUIRED) +function(target_optional_compile_definitions _target _scope) + set(options FEATURE) + set(oneValueArgs NAME DESCRIPTION DEFAULT) + set(multiValueArgs ENABLED DISABLED) + cmake_parse_arguments(TOCD ${options} "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + option(${TOCD_NAME} "${TOCD_DESCRIPTION}" ${TOCD_DEFAULT}) + if (${${TOCD_NAME}}) + target_compile_definitions(${_target} ${_scope} ${TOCD_ENABLED}) + else() + target_compile_definitions(${_target} ${_scope} ${TOCD_DISABLED}) endif() - add_definitions(-DTORRENT_USE_OPENSSL) - include_directories(${OPENSSL_INCLUDE_DIR}) -else() - add_definitions(-DTORRENT_DISABLE_ENCRYPTION) - list(APPEND sources sha1) -endif (encryption) + if(${TOCD_FEATURE}) + add_feature_info(${TOCD_NAME} ${TOCD_NAME} "${TOCD_DESCRIPTION}") + endif() +endfunction() -if (NOT logging) - add_definitions(-DTORRENT_DISABLE_LOGGING) +macro(feature_option _name _description _default) + option(${_name} "${_description}" ${_default}) + add_feature_info(${_name} ${_name} "${_description}") +endmacro() + +# these options control target creation and thus have to be declared before the add_library() call +feature_option(BUILD_SHARED_LIBS "build libtorrent as a shared library" ON) +feature_option(static_runtime "build libtorrent with static runtime" OFF) + +macro(find_public_dependency _name) + find_package(${_name} ${ARGN}) + string(TOUPPER "${_name}" _name_uppercased) + if (${_name}_FOUND OR ${_name_uppercased}_FOUND) + # Dependencies to be used below for generating Config.cmake file + # We don't need the 'REQUIRED' argument there + set(_args "${_name}") + list(APPEND _args "${ARGN}") + list(REMOVE_ITEM _args "REQUIRED") + list(REMOVE_ITEM _args "") # just in case + string(REPLACE ";" " " _args "${_args}") + list(APPEND _package_dependencies "${_args}") + endif() +endmacro() + +find_public_dependency(Threads REQUIRED) + +if(static_runtime) + include(ucm_flags) + ucm_set_runtime(STATIC) + set(Boost_USE_MULTITHREADED ON) + set(Boost_USE_STATIC_RUNTIME ON) + set(OPENSSL_USE_STATIC_LIBS TRUE) + set(OPENSSL_MSVC_STATIC_RT TRUE) endif() -foreach(s ${sources}) - list(APPEND sources2 src/${s}) -endforeach(s) - -if (dht) - foreach(s ${kademlia_sources}) - list(APPEND sources2 src/kademlia/${s}) - endforeach(s) - foreach(s ${ed25519_sources}) - list(APPEND sources2 ed25519/src/${s}) - endforeach(s) -else() - add_definitions(-DTORRENT_DISABLE_DHT) +if (NOT BUILD_SHARED_LIBS) + set(Boost_USE_STATIC_LIBS ON) endif() -if (shared) - add_library(torrent-rasterbar SHARED ${sources2}) +add_library(torrent-rasterbar ${sources}) + +if (BUILD_SHARED_LIBS) target_compile_definitions(torrent-rasterbar PRIVATE TORRENT_BUILDING_SHARED INTERFACE TORRENT_LINKING_SHARED ) - if(NOT MSVC) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fvisibility=hidden") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -fvisibility-inlines-hidden") - endif() -else() - if(static_runtime) - # fix /MT flag: - set(CompilerFlags - CMAKE_CXX_FLAGS - CMAKE_CXX_FLAGS_DEBUG - CMAKE_CXX_FLAGS_RELWITHDEBINFO - CMAKE_CXX_FLAGS_RELEASE - CMAKE_C_FLAGS - CMAKE_C_FLAGS_DEBUG - CMAKE_CXX_FLAGS_RELWITHDEBINFO - CMAKE_C_FLAGS_RELEASE - ) - foreach(CompilerFlag ${CompilerFlags}) - string(REPLACE "/MD" "/MT" ${CompilerFlag} "${${CompilerFlag}}") - endforeach() - set(Boost_USE_MULTITHREADED ON) - - set(Boost_USE_STATIC_RUNTIME ON) - endif() - set(Boost_USE_STATIC_LIBS ON) - add_library(torrent-rasterbar STATIC ${sources2}) endif() -target_compile_definitions(torrent-rasterbar PRIVATE TORRENT_BUILDING_LIBRARY) +set_target_properties(torrent-rasterbar + PROPERTIES + CXX_VISIBILITY_PRESET "hidden" + VISIBILITY_INLINES_HIDDEN "true" + VERSION ${PROJECT_VERSION} + SOVERSION ${SOVERSION} +) + +target_compile_definitions(torrent-rasterbar + PUBLIC + $<$:TORRENT_DEBUG> + PRIVATE + TORRENT_BUILDING_LIBRARY + _FILE_OFFSET_BITS=64 + BOOST_EXCEPTION_DISABLE + BOOST_ASIO_ENABLE_CANCELIO +) + +target_include_directories(torrent-rasterbar + PUBLIC + $ + $ +) + +target_link_libraries(torrent-rasterbar + PUBLIC + Threads::Threads +) + +feature_option(build_tests "build tests" OFF) +if(NOT build_tests) # tests require deprecated symbols + target_optional_compile_definitions(torrent-rasterbar PUBLIC FEATURE NAME deprecated-functions DEFAULT ON + DESCRIPTION "enable deprecated functions for backwards compatibility" DISABLED TORRENT_NO_DEPRECATE) +endif() +feature_option(build_examples "build examples" OFF) +feature_option(build_tools "build tools" OFF) +feature_option(python-bindings "build python bindings" OFF) + +target_optional_compile_definitions(torrent-rasterbar PUBLIC FEATURE NAME logging DEFAULT ON + DESCRIPTION "build with logging" DISABLED TORRENT_DISABLE_LOGGING) +target_optional_compile_definitions(torrent-rasterbar PUBLIC FEATURE NAME pool-allocators DEFAULT ON + DESCRIPTION "Uses a pool allocator for disk and piece buffers" DISABLED TORRENT_DISABLE_POOL_ALLOCATOR) +target_optional_compile_definitions(torrent-rasterbar PUBLIC FEATURE NAME resolve-countries DEFAULT ON + DESCRIPTION "enable support for resolving countries from peer IPs" DISABLED TORRENT_DISABLE_RESOLVE_COUNTRIES) +target_optional_compile_definitions(torrent-rasterbar PUBLIC FEATURE NAME unicode DEFAULT ON + DESCRIPTION "enable unicode support" ENABLED UNICODE _UNICODE) + +feature_option(dht "enable support for Mainline DHT" ON) +feature_option(encryption "link against openssl and enable encryption" ON) +feature_option(exceptions "build with exception support" ON) + +if (dht) + target_sources(torrent-rasterbar PRIVATE ${kademlia_sources} ${ed25519_sources}) +else() + target_compile_definitions(torrent-rasterbar PUBLIC TORRENT_DISABLE_DHT) +endif() + +if (encryption) + find_public_dependency(OpenSSL REQUIRED) + set_package_properties(OpenSSL + PROPERTIES + URL "https://www.openssl.org/" + DESCRIPTION "Full-strength general purpose cryptography library" + TYPE RECOMMENDED + PURPOSE "Provides encryption support to libtorrent" + ) + target_sources(torrent-rasterbar PRIVATE src/mpi src/pe_crypto) + target_link_libraries(torrent-rasterbar PUBLIC OpenSSL::SSL) + target_compile_definitions(torrent-rasterbar PUBLIC TORRENT_USE_OPENSSL) +else() + target_sources(torrent-rasterbar PRIVATE src/sha1) + target_compile_definitions(torrent-rasterbar PUBLIC TORRENT_DISABLE_ENCRYPTION) +endif() + + +option(tcmalloc "link against google performance tools tcmalloc" OFF) # C++ standard and Boost requirements are connected: # 1. With C++11 onward, we require Boost system component, with C++03 we need chrono and random components too @@ -263,9 +325,10 @@ if (NOT cxx_std_11 IN_LIST CMAKE_CXX_COMPILE_FEATURES) list(APPEND required_boost_components chrono random) endif() # Boost -if(NOT DEFINED Boost_INCLUDE_DIR OR NOT DEFINED Boost_LIBRARIES) - find_package(Boost REQUIRED COMPONENTS ${required_boost_components}) -endif() +find_public_dependency(Boost REQUIRED COMPONENTS ${required_boost_components}) +target_include_directories(torrent-rasterbar PUBLIC ${Boost_INCLUDE_DIRS}) +target_link_libraries(torrent-rasterbar PUBLIC ${Boost_SYSTEM_LIBRARY}) + # now test the second requirement: if (Boost_VERSION VERSION_GREATER_EQUAL 106600) if (NOT cxx_std_11 IN_LIST CMAKE_CXX_COMPILE_FEATURES) @@ -278,89 +341,58 @@ endif() if (cxx_std_14 IN_LIST CMAKE_CXX_COMPILE_FEATURES) target_compile_features(torrent-rasterbar PUBLIC cxx_std_14) message(STATUS "Building in C++14 mode") - set(CXX_MODE_COMPILE_OPTION -std=c++14) elseif(cxx_std_11 IN_LIST CMAKE_CXX_COMPILE_FEATURES) target_compile_features(torrent-rasterbar PUBLIC cxx_std_11) message(STATUS "Building in C++11 mode") - set(CXX_MODE_COMPILE_OPTION -std=c++11) endif() -include_directories(${Boost_INCLUDE_DIRS}) -target_link_libraries(torrent-rasterbar ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) - -# this works around a bug in asio in boost-1.39 -#add_definitions(-DBOOST_ASIO_HASH_MAP_BUCKETS=1021 -D__USE_W32_SOCKETS -DWIN32_LEAN_AND_MEAN ) +target_link_libraries(torrent-rasterbar PUBLIC ${Boost_LIBRARIES}) if (WIN32) - target_link_libraries(torrent-rasterbar wsock32 ws2_32 Iphlpapi) - target_link_libraries(torrent-rasterbar debug dbghelp) + target_link_libraries(torrent-rasterbar + PRIVATE + wsock32 ws2_32 Iphlpapi + debug dbghelp + ) add_definitions(-D_WIN32_WINNT=0x0600) # prevent winsock1 to be included add_definitions(-DWIN32_LEAN_AND_MEAN) if (MSVC) - add_definitions(-DBOOST_ALL_NO_LIB) - # for multicore compilation - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP") - # increase the number of sections for obj files - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj") + target_compile_definitions(torrent-rasterbar + PUBLIC + BOOST_ALL_NO_LIB + _SCL_SECURE_NO_DEPRECATE _CRT_SECURE_NO_DEPRECATE # disable bogus deprecation warnings on msvc8 + ) + target_compile_options(torrent-rasterbar + PRIVATE + /Zc:wchar_t /Zc:forScope # these compiler settings just make the compiler standard conforming + /MP # for multi-core compilation + /bigobj # increase the number of sections for obj files + ) endif() endif() -if (encryption) - target_link_libraries(torrent-rasterbar ${OPENSSL_LIBRARIES}) -endif() - -if (NOT pool-allocators) - add_definitions(-DTORRENT_DISABLE_POOL_ALLOCATOR) -endif() - -if (NOT resolve-countries) - add_definitions(-DTORRENT_DISABLE_RESOLVE_COUNTRIES) -endif() - -if (unicode) - add_definitions(-DUNICODE -D_UNICODE) -endif() - -if (NOT deprecated-functions) - add_definitions(-DTORRENT_NO_DEPRECATE) -endif() - if (exceptions) if (MSVC) - add_definitions(/EHsc) + target_compile_options(torrent-rasterbar PUBLIC /EHsc) else (MSVC) - add_definitions(-fexceptions) + target_compile_options(torrent-rasterbar PUBLIC -fexceptions) endif (MSVC) else() if (MSVC) - add_definitions(-D_HAS_EXCEPTIONS=0) + target_compile_definitions(torrent-rasterbar PUBLIC _HAS_EXCEPTIONS=0) else (MSVC) - add_definitions(-fno-exceptions) + target_compile_options(torrent-rasterbar PUBLIC -fno-exceptions) endif (MSVC) endif() -if (MSVC) -# disable bogus deprecation warnings on msvc8 - add_definitions(-D_SCL_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_DEPRECATE) -# these compiler settings just makes the compiler standard conforming - add_definitions(/Zc:wchar_t /Zc:forScope) -# for multi-core compilation - add_definitions(/MP) - -#$(SolutionDir)msvc,release:/OPT:ICF=5 -#$(SolutionDir)msvc,release:/OPT:REF -elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") +if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") add_definitions(-Wno-c++11-extensions) add_definitions(-fcolor-diagnostics) endif() -add_definitions(-D_FILE_OFFSET_BITS=64) -add_definitions(-DBOOST_EXCEPTION_DISABLE) -add_definitions(-DBOOST_ASIO_ENABLE_CANCELIO) - if (tcmalloc) - target_link_libraries(torrent-rasterbar tcmalloc) + target_link_libraries(torrent-rasterbar PRIVATE tcmalloc) endif() set_target_properties(torrent-rasterbar PROPERTIES @@ -376,26 +408,79 @@ foreach (s ${COMPILETIME_OPTIONS_LIST}) set (COMPILETIME_OPTIONS "${COMPILETIME_OPTIONS} -D${s}") endforeach (s) -configure_file(libtorrent-rasterbar-cmake.pc.in libtorrent-rasterbar.pc) +generate_and_install_pkg_config_file(torrent-rasterbar) -string (COMPARE EQUAL "${CMAKE_SIZEOF_VOID_P}" "8" IS64BITS) +install(TARGETS torrent-rasterbar EXPORT LibtorrentRasterbarTargets + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) +install(DIRECTORY include/libtorrent DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} FILES_MATCHING PATTERN "*.h*") -if (IS64BITS AND RESPECTLIB64) - set (LIBDIR "lib64") +# === generate a CMake Config File === +include(CMakePackageConfigHelpers) +set(ConfigPackageLocation ${CMAKE_INSTALL_LIBDIR}/cmake/LibtorrentRasterbar) +string(REGEX REPLACE "([^;]+)" "find_dependency(\\1)" _find_dependency_calls "${_package_dependencies}") +string(REPLACE ";" "\n" _find_dependency_calls "${_find_dependency_calls}") + +if(CMAKE_VERSION VERSION_LESS "3.11.0") + set(_compatibility ExactVersion) else() - set (LIBDIR "lib") + set(_compatibility SameMinorVersion) endif() -install(TARGETS torrent-rasterbar DESTINATION ${LIBDIR}) -install(DIRECTORY include/libtorrent - DESTINATION include - PATTERN ".svn" EXCLUDE) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libtorrent-rasterbar.pc DESTINATION ${LIBDIR}/pkgconfig) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/LibtorrentRasterbar/LibtorrentRasterbarConfigVersion.cmake" + VERSION ${libtorrent_VERSION} + COMPATIBILITY ${_compatibility} +) -# === set up examples directory as an independent project === -file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/examples) -configure_file(examples/run_cmake.sh.in examples/run_cmake.sh) -# to build the examples, run examples/run_cmake.sh after building libtorrent +export(EXPORT LibtorrentRasterbarTargets + FILE "${CMAKE_CURRENT_BINARY_DIR}/LibtorrentRasterbar/LibtorrentRasterbarTargets.cmake" + NAMESPACE LibtorrentRasterbar:: +) + +configure_package_config_file(LibtorrentRasterbarConfig.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/LibtorrentRasterbar/LibtorrentRasterbarConfig.cmake" + INSTALL_DESTINATION "${ConfigPackageLocation}" + NO_SET_AND_CHECK_MACRO + NO_CHECK_REQUIRED_COMPONENTS_MACRO +) + +install(EXPORT LibtorrentRasterbarTargets + NAMESPACE + LibtorrentRasterbar:: + DESTINATION + ${ConfigPackageLocation} +) +install( + FILES + "${CMAKE_CURRENT_BINARY_DIR}/LibtorrentRasterbar/LibtorrentRasterbarConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/LibtorrentRasterbar/LibtorrentRasterbarConfigVersion.cmake" + DESTINATION + ${ConfigPackageLocation} +) + +install( + FILES + ${CMAKE_CURRENT_SOURCE_DIR}/examples/cmake/FindLibtorrentRasterbar.cmake + DESTINATION + ${CMAKE_INSTALL_DATADIR}/cmake/Modules +) + +include(CheckCXXCompilerFlag) + +add_subdirectory(bindings) + +# === build tools === +if (build_tools) + add_subdirectory(tools) +endif() + +# === build examples === +if (build_examples) + add_subdirectory(examples) +endif() # === build tests === if(build_tests) @@ -404,3 +489,5 @@ if(build_tests) target_compile_definitions(torrent-rasterbar PUBLIC TORRENT_EXPORT_EXTRA) add_subdirectory(test) endif() + +feature_summary(DEFAULT_DESCRIPTION WHAT ALL) diff --git a/LibtorrentRasterbarConfig.cmake.in b/LibtorrentRasterbarConfig.cmake.in new file mode 100644 index 000000000..5fb0da0c2 --- /dev/null +++ b/LibtorrentRasterbarConfig.cmake.in @@ -0,0 +1,16 @@ +# - Config file for the @PROJECT_NAME@ package +# It defines the following variables +# @PROJECT_NAME@_INCLUDE_DIRS - include directories for @PROJECT_NAME@ +# @PROJECT_NAME@_LIBRARIES - libraries to link against + +@PACKAGE_INIT@ + +include(CMakeFindDependencyMacro) +@_find_dependency_calls@ + +include("${CMAKE_CURRENT_LIST_DIR}/LibtorrentRasterbarTargets.cmake") + +get_target_property(@PROJECT_NAME@_INCLUDE_DIRS LibtorrentRasterbar::torrent-rasterbar INTERFACE_INCLUDE_DIRECTORIES) +get_target_property(_lt_iface_link_libraries LibtorrentRasterbar::torrent-rasterbar INTERFACE_LINK_LIBRARIES) +get_target_property(_lt_imported_location LibtorrentRasterbar::torrent-rasterbar IMPORTED_LOCATION) +set(@PROJECT_NAME@_LIBRARIES "${_lt_imported_location};${_lt_iface_link_libraries}") diff --git a/Makefile.am b/Makefile.am index bac1fe0de..49eb59a49 100644 --- a/Makefile.am +++ b/Makefile.am @@ -120,10 +120,15 @@ EXTRA_DIST = \ setup.py \ LICENSE \ README.rst \ + cmake/Modules/FindLibGcrypt.cmake \ + cmake/Modules/GeneratePkgConfig.cmake \ + cmake/Modules/ucm_flags.cmake \ + cmake/Modules/GeneratePkgConfig/generate-pkg-config.cmake.in \ + cmake/Modules/GeneratePkgConfig/pkg-config.cmake.in \ + cmake/Modules/GeneratePkgConfig/target-compile-settings.cmake.in \ $(DOCS_PAGES) \ $(DOCS_IMAGES) \ $(ED25519_SOURCE) pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = libtorrent-rasterbar.pc - diff --git a/bindings/CMakeLists.txt b/bindings/CMakeLists.txt new file mode 100644 index 000000000..5dd618f7c --- /dev/null +++ b/bindings/CMakeLists.txt @@ -0,0 +1,3 @@ +if (python-bindings) + add_subdirectory(python) +endif() diff --git a/bindings/Makefile.am b/bindings/Makefile.am index 929b41f11..39ca193d9 100644 --- a/bindings/Makefile.am +++ b/bindings/Makefile.am @@ -1,4 +1,6 @@ SUBDIRS = python -EXTRA_DIST = README.txt +EXTRA_DIST = \ + CMakeLists.txt \ + README.txt diff --git a/bindings/python/CMakeLists.txt b/bindings/python/CMakeLists.txt new file mode 100644 index 000000000..cdbfa98be --- /dev/null +++ b/bindings/python/CMakeLists.txt @@ -0,0 +1,148 @@ +# To build python bindings we need a python executable and boost python module. Unfortunately, +# their names might not be interlinked and we can not implement a general solution. +# The code below assumes default boost installation, when the module for python 2 is named +# 'python' and the module for python 3 is named 'python3'. +# To customize that one can provide a name for the Boost::python module via +# 'boost-python-module-name' variable when invoking cmake. +# E.g. on Gentoo with python 3.6 and Boost::python library name 'libboost_python-3.6.so' +# the parameter would be -Dboost-python-module-name="python-3.6". + +# The extension module and the cpython executable have to use the same C runtime library. On Windows +# Python is compiled with MSVC and we will test MSVC version to make sure that it is the same for +# the given Python version and our extension module. See https://wiki.python.org/moin/WindowsCompilers +# for details. We provide a flag to skip this test for whatever reason (pass -Dskip-python-runtime-test=True) + +# Sets _ret to a list of python versions (major.minor) that use the same MSVC runtime as this build does +# assumes MSVC was detected already +# See https://en.wikipedia.org/wiki/Microsoft_Visual_C++#Internal_version_numbering +function(_get_compatible_python_versions _ret) + if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 15 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 16) + list(APPEND _tmp 2.6 2.7 3.0 3.1 3.2) + elseif(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 16 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 17) + list(APPEND _tmp 3.3 3.4) + elseif(CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 20) + list(APPEND _tmp 3.5 3.6) + endif() + set(${_ret} ${_tmp} PARENT_SCOPE) +endfunction() + + +if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC" AND NOT skip-python-runtime-test) + _get_compatible_python_versions(Python_ADDITIONAL_VERSIONS) +endif() + +find_package(PythonInterp REQUIRED) +if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC" AND NOT skip-python-runtime-test) + message(STATUS "Testing found python version. Requested: ${Python_ADDITIONAL_VERSIONS}, found: ${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") + if (NOT "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}" IN_LIST Python_ADDITIONAL_VERSIONS) + message(FATAL_ERROR "Incompatible Python and C runtime: MSVC ${CMAKE_CXX_COMPILER_VERSION} and Python ${PYTHON_VERSION_STRING}") + endif() +endif() + +set(Python_ADDITIONAL_VERSIONS "${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}") +find_package(PythonLibs REQUIRED) + +if (NOT boost-python-module-name) + # use active python + if (PYTHON_VERSION_STRING VERSION_GREATER_EQUAL "3") + set(_boost-python-module-name "python${PYTHON_VERSION_MAJOR}") + else() + set(_boost-python-module-name "python") # to overwrite possible value from a previous run + endif() +endif() + +set(boost-python-module-name ${_boost-python-module-name} CACHE STRING "Boost:python module name, e.g. 'pythom-3.6'") + +find_package(Boost REQUIRED COMPONENTS ${boost-python-module-name}) + +python_add_module(python-libtorrent + src/alert.cpp + src/big_number.cpp + src/converters.cpp + src/create_torrent.cpp + src/datetime.cpp + src/entry.cpp + src/error_code.cpp + src/fingerprint.cpp + src/ip_filter.cpp + src/magnet_uri.cpp + src/module.cpp + src/peer_info.cpp + src/session.cpp + src/session_settings.cpp + src/string.cpp + src/torrent_handle.cpp + src/torrent_info.cpp + src/torrent_status.cpp + src/utility.cpp + src/version.cpp +) + +set_target_properties(python-libtorrent + PROPERTIES + OUTPUT_NAME libtorrent +) + +target_include_directories(python-libtorrent + PRIVATE + ${PYTHON_INCLUDE_DIRS} +) + +string(TOUPPER "${boost-python-module-name}" boost_python_module_name_uppercase) +target_link_libraries(python-libtorrent + PRIVATE + torrent-rasterbar + ${Boost_${boost_python_module_name_uppercase}_LIBRARY} + # Boost::python adds that but without a path to the library. Therefore we have to either + # provide the path (but, unfortunately, FindPythonLibs.cmake does not return the library dir), + # or give the full file name here (this FindPythonLibs.cmake provides to us). + ${PYTHON_LIBRARIES} +) + +# Bindings module uses deprecated libtorrent features, thus we disable these warnings +if (CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + check_cxx_compiler_flag("-Wno-deprecated-declarations" _WNO_DEPRECATED_DECLARATIONS) + if (_WNO_DEPRECATED_DECLARATIONS) + target_compile_options(python-libtorrent PRIVATE -Wno-deprecated-declarations) + endif() +endif() + +execute_process(COMMAND + ${PYTHON_EXECUTABLE} -c "import distutils.sysconfig; +print(';'.join(map(str, [ + distutils.sysconfig.get_python_lib(plat_specific=True, prefix=''), + distutils.sysconfig.get_config_var('EXT_SUFFIX') +])))" + OUTPUT_VARIABLE _python_sysconfig_vars OUTPUT_STRIP_TRAILING_WHITESPACE) + +list(GET _python_sysconfig_vars 0 PYTHON_SITE_PACKAGES) +list(GET _python_sysconfig_vars 1 PYTHON_EXT_SUFFIX) + +message(STATUS "Python site packages: ${PYTHON_SITE_PACKAGES}") +# python 2 does not provide the 'EXT_SUFFIX' sysconfig variable, so we use cmake default then +if (NOT "${PYTHON_EXT_SUFFIX}" STREQUAL "None") + message(STATUS "Python extension suffix: ${PYTHON_EXT_SUFFIX}") + # we mimic the name, created by setuptools + # example: libtorrent.cpython-36m-x86_64-linux-gnu.so + set_target_properties(python-libtorrent PROPERTIES SUFFIX ${PYTHON_EXT_SUFFIX}) +endif() + +set(SETUP_PY_IN "${CMAKE_CURRENT_SOURCE_DIR}/setup.py.cmake.in") +set(SETUP_PY "${CMAKE_CURRENT_BINARY_DIR}/setup.py") +set(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/timestamp") +set(DEPS python-libtorrent "${SETUP_PY}") + +configure_file(${SETUP_PY_IN} ${SETUP_PY} @ONLY) + +add_custom_command(OUTPUT ${OUTPUT} + COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} build -b "${CMAKE_CURRENT_SOURCE_DIR}" + COMMAND ${PYTHON_EXECUTABLE} ${SETUP_PY} egg_info -b "${CMAKE_CURRENT_SOURCE_DIR}" + COMMAND ${CMAKE_COMMAND} -E touch ${OUTPUT} + DEPENDS ${DEPS}) + +add_custom_target(python_bindings ALL DEPENDS ${OUTPUT}) + + +install(TARGETS python-libtorrent DESTINATION "${PYTHON_SITE_PACKAGES}") +install(DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/libtorrent.egg-info" DESTINATION "${PYTHON_SITE_PACKAGES}") + diff --git a/bindings/python/Makefile.am b/bindings/python/Makefile.am index 41b99428b..14605b729 100644 --- a/bindings/python/Makefile.am +++ b/bindings/python/Makefile.am @@ -1,5 +1,6 @@ EXTRA_DIST = \ + CMakeLists.txt \ Jamfile \ setup.py \ client.py \ diff --git a/bindings/python/setup.py.cmake.in b/bindings/python/setup.py.cmake.in new file mode 100644 index 000000000..7fdcfcf1a --- /dev/null +++ b/bindings/python/setup.py.cmake.in @@ -0,0 +1,15 @@ +from setuptools import setup +import platform + +setup( + name='libtorrent', + version='@libtorrent_VERSION@', + author='Arvid Norberg', + author_email='arvid@libtorrent.org', + description='Python bindings for libtorrent-rasterbar', + long_description='Python bindings for libtorrent-rasterbar', + url='http://libtorrent.org', + platforms=[platform.system() + '-' + platform.machine()], + license='BSD', + package_dir = {'': '@CMAKE_CURRENT_BINARY_DIR@'} +) diff --git a/cmake/Modules/FindLibGcrypt.cmake b/cmake/Modules/FindLibGcrypt.cmake new file mode 100644 index 000000000..dcf1c984c --- /dev/null +++ b/cmake/Modules/FindLibGcrypt.cmake @@ -0,0 +1,127 @@ +#.rst: +# FindLibGcrypt +# ------------- +# +# Try to find libgcrypt. +# +# This will define the following variables: +# +# ``LibGcrypt_FOUND`` +# True if libgcrypt is available. +# +# ``LibGcrypt_VERSION`` +# The version of LibGcrypt +# +# ``LibGcrypt_INCLUDE_DIRS`` +# This should be passed to target_include_directories() if +# the target is not used for linking +# +# ``LibGcrypt_LIBRARIES`` +# This can be passed to target_link_libraries() instead of +# the ``LibGcrypt::LibGcrypt`` target +# +# If ``LibGcrypt_FOUND`` is TRUE, the following imported target +# will be available: +# +# ``LibGcrypt::LibGcrypt`` +# The libgcrypt library +# +# Since 1.9.50. + +#============================================================================= +# Copyright 2007 Charles Connell (This was based upon FindKopete.cmake) +# Copyright 2010 Joris Guisson +# Copyright 2016 Christophe Giboudeaux +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# +# 1. Redistributions of source code must retain the copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. The name of the author may not be used to endorse or promote products +# derived from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +#============================================================================= + +find_path(LibGcrypt_INCLUDE_DIRS + NAMES gcrypt.h + PATH_SUFFIXES libgcrypt +) + +find_library(LibGcrypt_LIBRARIES + NAMES gcrypt +) + +if(MSVC) + find_library(LibGcrypt_LIBRARIES_DEBUG + NAMES gcryptd + ) + + if(NOT LibGcrypt_LIBRARIES_DEBUG) + unset(LibGcrypt_LIBRARIES CACHE) + endif() + + if(MSVC_IDE) + if(NOT (LibGcrypt_LIBRARIES_DEBUG AND LibGcrypt_LIBRARIES)) + message(STATUS + "\nCould NOT find the debug AND release version of the libgcrypt library.\n + You need to have both to use MSVC projects.\n + Please build and install both libgcrypt libraries first.\n" + ) + unset(LibGcrypt_LIBRARIES CACHE) + endif() + else() + string(TOLOWER ${CMAKE_BUILD_TYPE} CMAKE_BUILD_TYPE_TOLOWER) + if(CMAKE_BUILD_TYPE_TOLOWER MATCHES debug) + set(LibGcrypt_LIBRARIES ${LibGcrypt_LIBRARIES_DEBUG}) + endif() + endif() +endif() + +# Get version from gcrypt.h +# #define GCRYPT_VERSION "1.6.4" +if(LibGcrypt_INCLUDE_DIRS AND LibGcrypt_LIBRARIES) + file(STRINGS ${LibGcrypt_INCLUDE_DIRS}/gcrypt.h _GCRYPT_H REGEX "^#define GCRYPT_VERSION[ ]+.*$") + string(REGEX REPLACE "^.*GCRYPT_VERSION[ ]+\"([0-9]+).([0-9]+).([0-9]+).*\".*$" "\\1" LibGcrypt_MAJOR_VERSION "${_GCRYPT_H}") + string(REGEX REPLACE "^.*GCRYPT_VERSION[ ]+\"([0-9]+).([0-9]+).([0-9]+).*\".*$" "\\2" LibGcrypt_MINOR_VERSION "${_GCRYPT_H}") + string(REGEX REPLACE "^.*GCRYPT_VERSION[ ]+\"([0-9]+).([0-9]+).([0-9]+).*\".*$" "\\3" LibGcrypt_PATCH_VERSION "${_GCRYPT_H}") + + set(LibGcrypt_VERSION "${LibGcrypt_MAJOR_VERSION}.${LibGcrypt_MINOR_VERSION}.${LibGcrypt_PATCH_VERSION}") + unset(_GCRYPT_H) +endif() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LibGcrypt + FOUND_VAR LibGcrypt_FOUND + REQUIRED_VARS LibGcrypt_INCLUDE_DIRS LibGcrypt_LIBRARIES + VERSION_VAR LibGcrypt_VERSION +) + +if(LibGcrypt_FOUND AND NOT TARGET LibGcrypt::LibGcrypt) + add_library(LibGcrypt::LibGcrypt UNKNOWN IMPORTED) + set_target_properties(LibGcrypt::LibGcrypt PROPERTIES + IMPORTED_LOCATION "${LibGcrypt_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${LibGcrypt_INCLUDE_DIRS}") +endif() + +mark_as_advanced(LibGcrypt_INCLUDE_DIRS LibGcrypt_LIBRARIES) + +include(FeatureSummary) +set_package_properties(LibGcrypt PROPERTIES + URL "http://directory.fsf.org/wiki/Libgcrypt" + DESCRIPTION "General purpose crypto library based on the code used in GnuPG." +) diff --git a/cmake/Modules/GeneratePkgConfig.cmake b/cmake/Modules/GeneratePkgConfig.cmake new file mode 100644 index 000000000..2bb76a0ef --- /dev/null +++ b/cmake/Modules/GeneratePkgConfig.cmake @@ -0,0 +1,187 @@ +# This module provides generate_and_install_pkg_config_file() function. +# The function takes target name and expects a fully configured project, i.e. with set version and +# description. The function extracts interface libraries, include dirs, definitions and options +# from the target and generates pkg-config file with install() command +# The function expands imported targets and generator expressions + +# save the current file dir for later use in the generate_and_install_pkg_config_file() function +set(_GeneratePkGConfigDir "${CMAKE_CURRENT_LIST_DIR}/GeneratePkgConfig") + +include(GNUInstallDirs) + +function(_compile_features_to_gcc_flags _res _features) + set(features ${_features}) + # leave only cxx_std_nn items + list(FILTER features INCLUDE REGEX cxx_std_) + if (${features} STREQUAL "") + set(${_res} "" PARENT_SCOPE) + else() + # if there are more than a single cxx_std_nn feature... + list(SORT features) + # take the most recent standard, i.e. the last element + list(GET features -1 standard) + # cmake calls it cxx_std_98, but we (obviously) want -std=c++03 + string(REPLACE 98 03 standard "${standard}") + string(REPLACE cxx_std_ -std=c++ standard "${standard}") + set(${_res} "${standard}" PARENT_SCOPE) + endif() +endfunction() + +function(_get_target_property_merging_configs _var_name _target_name _propert_name) + get_target_property(vals ${_target_name} ${_propert_name}) + if (NOT vals) + if (CMAKE_BUILD_TYPE) + list(APPEND configs ${CMAKE_BUILD_TYPE}) + elseif() + list(APPEND configs ${CMAKE_CONFIGURATION_TYPES}) + endif() + foreach(cfg ${configs}) + string(TOUPPER "${cfg}" UPPERCFG) + get_target_property(mapped_configs ${_target_name} "MAP_IMPORTED_CONFIG_${UPPERCFG}") + if (mapped_configs) + list(GET "${mapped_configs}" 0 target_cfg) + else() + set(target_cfg "${UPPERCFG}") + endif() + get_target_property(val_for_cfg ${_target_name} "${_propert_name}_${target_cfg}") + if (val_for_cfg) + list(APPEND vals "$<$:${val_for_cfg}>") + endif() + endforeach() + endif() + # HACK for static libraries cmake populates link dependencies as $. + # pkg-config does not support special handling for static libraries and as such we will remove + # that generator expression + string(REPLACE "$") + + configure_file("${_GeneratePkGConfigDir}/generate-pkg-config.cmake.in" + "${_generate_target_dir}/${cfg}/generate-pkg-config.cmake" @ONLY) + + install(SCRIPT "${_generate_target_dir}/${cfg}/generate-pkg-config.cmake") + endforeach() + endif() +endfunction() diff --git a/cmake/Modules/GeneratePkgConfig/generate-pkg-config.cmake.in b/cmake/Modules/GeneratePkgConfig/generate-pkg-config.cmake.in new file mode 100644 index 000000000..807876f10 --- /dev/null +++ b/cmake/Modules/GeneratePkgConfig/generate-pkg-config.cmake.in @@ -0,0 +1,22 @@ +include(@_variables_file_name@) + +function (cmake_list_to_pkg_config _result _list _prefix) + set(_tmp_list "${_list}") + list(REMOVE_ITEM _tmp_list "") + # remove prefix from prefixed items + string(REGEX REPLACE "(^|;)(${_prefix})" "\\1" _tmp_list "${_tmp_list}") + # append 'prefix' to each element + string(REGEX REPLACE "([^;]+)" "${_prefix}\\1" _tmp_list "${_tmp_list}") + # transform cmake list into a space delimited list + string(REPLACE ";" " " _tmp_list "${_tmp_list}") + set(${_result} "${_tmp_list}" PARENT_SCOPE) +endfunction() + +cmake_list_to_pkg_config(_interface_link_libraries "${_TARGET_INTERFACE_LINK_LIBRARIES}" "-l") +cmake_list_to_pkg_config(_interface_definitions "${_TARGET_INTERFACE_DEFINITIONS}" "-D") +cmake_list_to_pkg_config(_interface_include_dirs "${_TARGET_INTERFACE_INCLUDE_DIRS}" "-I") +set(_interface_compile_options "${_TARGET_INTERFACE_COMPILE_OPTIONS}") +string(REPLACE ";" " " _interface_compile_options "${_interface_compile_options}") + +configure_file("@_pkg_config_file_template_filename@" "@_generate_target_dir@/@_output_name@.pc" @ONLY) +file(INSTALL "@_generate_target_dir@/@_output_name@.pc" DESTINATION "@CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_LIBDIR@/pkgconfig") diff --git a/cmake/Modules/GeneratePkgConfig/pkg-config.cmake.in b/cmake/Modules/GeneratePkgConfig/pkg-config.cmake.in new file mode 100644 index 000000000..435413472 --- /dev/null +++ b/cmake/Modules/GeneratePkgConfig/pkg-config.cmake.in @@ -0,0 +1,8 @@ +prefix=@CMAKE_INSTALL_PREFIX@ +libdir=${prefix}/@_INSTALL_LIBDIR@ + +Name: @_PROJECT_NAME@ +Description: @_PROJECT_DESCRIPTION@ +Version: @_PROJECT_VERSION@ +Libs: -L${libdir} -l@_TARGET_OUTPUT_NAME@ @_interface_link_libraries@ +Cflags: @_interface_compile_options@ @_interface_include_dirs@ @_interface_definitions@ diff --git a/cmake/Modules/GeneratePkgConfig/target-compile-settings.cmake.in b/cmake/Modules/GeneratePkgConfig/target-compile-settings.cmake.in new file mode 100644 index 000000000..e5090e3b8 --- /dev/null +++ b/cmake/Modules/GeneratePkgConfig/target-compile-settings.cmake.in @@ -0,0 +1,12 @@ +set(_TARGET_INTERFACE_LINK_LIBRARIES "@_interface_link_libraries@") +set(_TARGET_INTERFACE_COMPILE_OPTIONS "@_interface_compile_options@") +set(_TARGET_INTERFACE_INCLUDE_DIRS "@_interface_include_dirs@") +set(_TARGET_INTERFACE_DEFINITIONS "@_interface_definitions@") +set(_TARGET_OUTPUT_NAME "@_output_name@") + +set(_INSTALL_LIBDIR "@CMAKE_INSTALL_LIBDIR@") +set(_INSTALL_INCLUDEDIR "@CMAKE_INSTALL_INCLUDEDIR@") + +set(_PROJECT_NAME "@PROJECT_NAME@") +set(_PROJECT_DESCRIPTION "@PROJECT_DESCRIPTION@") +set(_PROJECT_VERSION "@PROJECT_VERSION@") diff --git a/cmake/Modules/ucm_flags.cmake b/cmake/Modules/ucm_flags.cmake new file mode 100644 index 000000000..7b3af2a2a --- /dev/null +++ b/cmake/Modules/ucm_flags.cmake @@ -0,0 +1,118 @@ +# taken from https://github.com/onqtam/ucm/blob/master/cmake/ucm.cmake + +# +# ucm.cmake - useful cmake macros +# +# Copyright (c) 2016 Viktor Kirilov +# +# Distributed under the MIT Software License +# See accompanying file LICENSE.txt or copy at +# https://opensource.org/licenses/MIT +# +# The documentation can be found at the library's page: +# https://github.com/onqtam/ucm + +include(CMakeParseArguments) + +# ucm_gather_flags +# Gathers all lists of flags for printing or manipulation +macro(ucm_gather_flags with_linker result) + set(${result} "") + # add the main flags without a config + list(APPEND ${result} CMAKE_C_FLAGS) + list(APPEND ${result} CMAKE_CXX_FLAGS) + if(${with_linker}) + list(APPEND ${result} CMAKE_EXE_LINKER_FLAGS) + list(APPEND ${result} CMAKE_MODULE_LINKER_FLAGS) + list(APPEND ${result} CMAKE_SHARED_LINKER_FLAGS) + list(APPEND ${result} CMAKE_STATIC_LINKER_FLAGS) + endif() + + if("${CMAKE_CONFIGURATION_TYPES}" STREQUAL "" AND NOT "${CMAKE_BUILD_TYPE}" STREQUAL "") + # handle single config generators - like makefiles/ninja - when CMAKE_BUILD_TYPE is set + string(TOUPPER ${CMAKE_BUILD_TYPE} config) + list(APPEND ${result} CMAKE_C_FLAGS_${config}) + list(APPEND ${result} CMAKE_CXX_FLAGS_${config}) + if(${with_linker}) + list(APPEND ${result} CMAKE_EXE_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_MODULE_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_SHARED_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_STATIC_LINKER_FLAGS_${config}) + endif() + else() + # handle multi config generators (like msvc, xcode) + foreach(config ${CMAKE_CONFIGURATION_TYPES}) + string(TOUPPER ${config} config) + list(APPEND ${result} CMAKE_C_FLAGS_${config}) + list(APPEND ${result} CMAKE_CXX_FLAGS_${config}) + if(${with_linker}) + list(APPEND ${result} CMAKE_EXE_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_MODULE_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_SHARED_LINKER_FLAGS_${config}) + list(APPEND ${result} CMAKE_STATIC_LINKER_FLAGS_${config}) + endif() + endforeach() + endif() +endmacro() + +# ucm_set_runtime +# Sets the runtime (static/dynamic) for msvc/gcc +macro(ucm_set_runtime) + cmake_parse_arguments(ARG "STATIC;DYNAMIC" "" "" ${ARGN}) + + if(ARG_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "unrecognized arguments: ${ARG_UNPARSED_ARGUMENTS}") + endif() + + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang" STREQUAL "") + message(AUTHOR_WARNING "ucm_set_runtime() does not support clang yet!") + endif() + + ucm_gather_flags(0 flags_configs) + + # add/replace the flags + # note that if the user has messed with the flags directly this function might fail + # - for example if with MSVC and the user has removed the flags - here we just switch/replace them + if("${ARG_STATIC}") + foreach(flags ${flags_configs}) + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + if(NOT ${flags} MATCHES "-static-libstdc\\+\\+") + set(${flags} "${${flags}} -static-libstdc++") + endif() + if(NOT ${flags} MATCHES "-static-libgcc") + set(${flags} "${${flags}} -static-libgcc") + endif() + elseif(MSVC) + if(${flags} MATCHES "/MD") + string(REGEX REPLACE "/MD" "/MT" ${flags} "${${flags}}") + endif() + endif() + endforeach() + elseif("${ARG_DYNAMIC}") + foreach(flags ${flags_configs}) + if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + if(${flags} MATCHES "-static-libstdc\\+\\+") + string(REGEX REPLACE "-static-libstdc\\+\\+" "" ${flags} "${${flags}}") + endif() + if(${flags} MATCHES "-static-libgcc") + string(REGEX REPLACE "-static-libgcc" "" ${flags} "${${flags}}") + endif() + elseif(MSVC) + if(${flags} MATCHES "/MT") + string(REGEX REPLACE "/MT" "/MD" ${flags} "${${flags}}") + endif() + endif() + endforeach() + endif() +endmacro() + +# ucm_print_flags +# Prints all compiler flags for all configurations +macro(ucm_print_flags) + ucm_gather_flags(1 flags_configs) + message("") + foreach(flags ${flags_configs}) + message("${flags}: ${${flags}}") + endforeach() + message("") +endmacro() diff --git a/configure.ac b/configure.ac index a5e4fe226..5bdf5b9ec 100644 --- a/configure.ac +++ b/configure.ac @@ -580,7 +580,6 @@ AC_CONFIG_FILES( [bindings/python/link_flags] [bindings/python/compile_flags] [libtorrent-rasterbar.pc] - [libtorrent-rasterbar-cmake.pc] ) AC_OUTPUT diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ba7595f33..428084cad 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,25 +1,12 @@ project(libtorrent-examples) -cmake_minimum_required(VERSION 2.6) -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") +cmake_minimum_required(VERSION 3.10) +list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/") -# Add extra include and library search directories so examples can optionally -# be built without a prior "make install" of libtorrent. -list(INSERT CMAKE_INCLUDE_PATH 0 "${CMAKE_CURRENT_SOURCE_DIR}/../include") -list(INSERT CMAKE_LIBRARY_PATH 0 "${CMAKE_CURRENT_BINARY_DIR}/..") - -# Also use the generated pkg-config file prior to "make install". -# In an independent project, these lines would simply not exist. -set(PKG_CONFIG_CHANGED_PATH "${CMAKE_CURRENT_BINARY_DIR}/..;$ENV{PKG_CONFIG_PATH}") -if(UNIX) - string(REPLACE ";" ":" PKG_CONFIG_CHANGED_PATH "${PKG_CONFIG_CHANGED_PATH}") -endif () -set(ENV{PKG_CONFIG_PATH} "${PKG_CONFIG_CHANGED_PATH}") - -find_package(LibtorrentRasterbar REQUIRED) -find_package(Boost REQUIRED COMPONENTS system) - -include_directories(${LibtorrentRasterbar_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) -add_definitions(${LibtorrentRasterbar_DEFINITIONS}) +if (TARGET torrent-rasterbar) + add_library(LibtorrentRasterbar::torrent-rasterbar ALIAS torrent-rasterbar) +else() + find_package(LibtorrentRasterbar REQUIRED) +endif() set(single_file_examples simple_client @@ -31,7 +18,7 @@ set(single_file_examples foreach(example ${single_file_examples}) add_executable(${example} "${example}.cpp") - target_link_libraries(${example} ${LibtorrentRasterbar_LIBRARIES} ${Boost_LIBRARIES}) + target_link_libraries(${example} LibtorrentRasterbar::torrent-rasterbar) endforeach(example) add_executable(client_test @@ -39,4 +26,4 @@ add_executable(client_test print.cpp torrent_view.cpp session_view.cpp) -target_link_libraries(client_test ${LibtorrentRasterbar_LIBRARIES} ${Boost_LIBRARIES}) +target_link_libraries(client_test LibtorrentRasterbar::torrent-rasterbar) diff --git a/examples/cmake/FindLibtorrentRasterbar.cmake b/examples/cmake/FindLibtorrentRasterbar.cmake index 1edeab971..c9ce1e8f4 100644 --- a/examples/cmake/FindLibtorrentRasterbar.cmake +++ b/examples/cmake/FindLibtorrentRasterbar.cmake @@ -1,6 +1,8 @@ # - Try to find libtorrent-rasterbar # -# If not using pkg-config, you can pre-set LibtorrentRasterbar_CUSTOM_DEFINITIONS +# This module tries to locate libtorrent-rasterbar Config.cmake files and uses pkg-config if available +# and the config file could not be found. +# If that does not work, you can pre-set LibtorrentRasterbar_CUSTOM_DEFINITIONS # for definitions unrelated to Boost's separate compilation (which are already # decided by the LibtorrentRasterbar_USE_STATIC_LIBS variable). # @@ -10,84 +12,139 @@ # LibtorrentRasterbar_LIBRARIES - The libraries needed to use libtorrent-rasterbar # LibtorrentRasterbar_DEFINITIONS - Compiler switches required for using libtorrent-rasterbar # LibtorrentRasterbar_OPENSSL_ENABLED - libtorrent-rasterbar uses and links against OpenSSL +# LibtorrentRasterbar::torrent-rasterbar imported target will be created -find_package(Threads REQUIRED) -find_package(PkgConfig QUIET) +# Let's begin with the config mode -if(PKG_CONFIG_FOUND) - pkg_check_modules(PC_LIBTORRENT_RASTERBAR QUIET libtorrent-rasterbar) +set(_exactKeyword "") +if (${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION_EXACT}) + set(_exactKeyword "EXACT") endif() -if(LibtorrentRasterbar_USE_STATIC_LIBS) - set(LibtorrentRasterbar_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) - set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) -endif() +find_package(LibtorrentRasterbar ${${CMAKE_FIND_PACKAGE_NAME}_FIND_VERSION} ${_exactKeyword} CONFIG) -if(PC_LIBTORRENT_RASTERBAR_FOUND) - set(LibtorrentRasterbar_DEFINITIONS ${PC_LIBTORRENT_RASTERBAR_CFLAGS}) +if (LibtorrentRasterbar_FOUND) + if (NOT ${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY) + message(STATUS "LibtorrentRasterbar package found in ${LibtorrentRasterbar_DIR}") + message(STATUS "LibtorrentRasterbar version: ${LibtorrentRasterbar_VERSION}") + endif() + # Extract target properties into this module variables + get_target_property(LibtorrentRasterbar_INCLUDE_DIRS LibtorrentRasterbar::torrent-rasterbar INTERFACE_INCLUDE_DIRECTORIES) + get_target_property(LibtorrentRasterbar_LIBRARIES LibtorrentRasterbar::torrent-rasterbar IMPORTED_LOCATION) + get_target_property(_iface_link_libs LibtorrentRasterbar::torrent-rasterbar INTERFACE_LINK_LIBRARIES) + list(APPEND LibtorrentRasterbar_LIBRARIES ${_iface_link_libs}) + get_target_property(LibtorrentRasterbar_DEFINITIONS LibtorrentRasterbar::torrent-rasterbar INTERFACE_COMPILE_DEFINITIONS) + get_target_property(_iface_compile_options LibtorrentRasterbar::torrent-rasterbar INTERFACE_COMPILE_OPTIONS) + list(APPEND LibtorrentRasterbar_DEFINITIONS ${_iface_compile_options}) + list(FIND _iface_link_libs "OpenSSL::SSL" _openssl_lib_index) + if (_openssl_lib_index GREATER -1) + set(LibtorrentRasterbar_OPENSSL_ENABLED TRUE) + else() + set(LibtorrentRasterbar_OPENSSL_ENABLED FALSE) + endif() else() - if(LibtorrentRasterbar_CUSTOM_DEFINITIONS) - set(LibtorrentRasterbar_DEFINITIONS ${LibtorrentRasterbar_CUSTOM_DEFINITIONS}) - else() - # Without pkg-config, we can't possibly figure out the correct build flags. - # libtorrent is very picky about those. Let's take a set of defaults and - # hope that they apply. If not, you the user are on your own. - set(LibtorrentRasterbar_DEFINITIONS - -DTORRENT_USE_OPENSSL - -DTORRENT_DISABLE_GEO_IP - -DBOOST_ASIO_ENABLE_CANCELIO - -DUNICODE -D_UNICODE -D_FILE_OFFSET_BITS=64) - endif() + find_package(Threads QUIET REQUIRED) + find_package(PkgConfig QUIET) - if(NOT LibtorrentRasterbar_USE_STATIC_LIBS) - list(APPEND LibtorrentRasterbar_DEFINITIONS - -DTORRENT_LINKING_SHARED - -DBOOST_SYSTEM_DYN_LINK -DBOOST_CHRONO_DYN_LINK) - endif() + if(PKG_CONFIG_FOUND) + pkg_check_modules(PC_LIBTORRENT_RASTERBAR QUIET libtorrent-rasterbar) + endif() + + if(LibtorrentRasterbar_USE_STATIC_LIBS) + set(LibtorrentRasterbar_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_FIND_LIBRARY_SUFFIXES}) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${CMAKE_STATIC_LIBRARY_SUFFIX}) + endif() + + if(PC_LIBTORRENT_RASTERBAR_FOUND) + set(LibtorrentRasterbar_DEFINITIONS ${PC_LIBTORRENT_RASTERBAR_CFLAGS_OTHER}) + else() + if(LibtorrentRasterbar_CUSTOM_DEFINITIONS) + set(LibtorrentRasterbar_DEFINITIONS ${LibtorrentRasterbar_CUSTOM_DEFINITIONS}) + else() + # Without pkg-config, we can't possibly figure out the correct build flags. + # libtorrent is very picky about those. Let's take a set of defaults and + # hope that they apply. If not, you the user are on your own. + set(LibtorrentRasterbar_DEFINITIONS + -DTORRENT_USE_OPENSSL + -DTORRENT_DISABLE_GEO_IP + -DBOOST_ASIO_ENABLE_CANCELIO + -D_FILE_OFFSET_BITS=64) + endif() + + if(NOT LibtorrentRasterbar_USE_STATIC_LIBS) + list(APPEND LibtorrentRasterbar_DEFINITIONS + -DTORRENT_LINKING_SHARED + -DBOOST_SYSTEM_DYN_LINK) + endif() + endif() + + if (NOT ${CMAKE_FIND_PACKAGE_NAME}_FIND_QUIETLY) + message(STATUS "libtorrent definitions: ${LibtorrentRasterbar_DEFINITIONS}") + endif() + + find_path(LibtorrentRasterbar_INCLUDE_DIR libtorrent + HINTS ${PC_LIBTORRENT_RASTERBAR_INCLUDEDIR} ${PC_LIBTORRENT_RASTERBAR_INCLUDE_DIRS} + PATH_SUFFIXES libtorrent-rasterbar) + + find_library(LibtorrentRasterbar_LIBRARY NAMES torrent-rasterbar + HINTS ${PC_LIBTORRENT_RASTERBAR_LIBDIR} ${PC_LIBTORRENT_RASTERBAR_LIBRARY_DIRS}) + + if(LibtorrentRasterbar_USE_STATIC_LIBS) + set(CMAKE_FIND_LIBRARY_SUFFIXES ${LibtorrentRasterbar_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) + endif() + + set(LibtorrentRasterbar_LIBRARIES ${LibtorrentRasterbar_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) + set(LibtorrentRasterbar_INCLUDE_DIRS ${LibtorrentRasterbar_INCLUDE_DIR}) + + if(NOT Boost_SYSTEM_FOUND) + find_package(Boost QUIET REQUIRED COMPONENTS system) + set(LibtorrentRasterbar_LIBRARIES + ${LibtorrentRasterbar_LIBRARIES} ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) + set(LibtorrentRasterbar_INCLUDE_DIRS + ${LibtorrentRasterbar_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) + endif() + + list(FIND LibtorrentRasterbar_DEFINITIONS -DTORRENT_USE_OPENSSL LibtorrentRasterbar_ENCRYPTION_INDEX) + if(LibtorrentRasterbar_ENCRYPTION_INDEX GREATER -1) + find_package(OpenSSL QUIET REQUIRED) + set(LibtorrentRasterbar_LIBRARIES ${LibtorrentRasterbar_LIBRARIES} ${OPENSSL_LIBRARIES}) + set(LibtorrentRasterbar_INCLUDE_DIRS ${LibtorrentRasterbar_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR}) + set(LibtorrentRasterbar_OPENSSL_ENABLED ON) + endif() + + include(FindPackageHandleStandardArgs) + # handle the QUIETLY and REQUIRED arguments and set LibtorrentRasterbar_FOUND to TRUE + # if all listed variables are TRUE + find_package_handle_standard_args(LibtorrentRasterbar DEFAULT_MSG + LibtorrentRasterbar_LIBRARY + LibtorrentRasterbar_INCLUDE_DIR + Boost_SYSTEM_FOUND + ) + + mark_as_advanced(LibtorrentRasterbar_INCLUDE_DIR LibtorrentRasterbar_LIBRARY + LibtorrentRasterbar_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES + LibtorrentRasterbar_ENCRYPTION_INDEX) + + if (LibtorrentRasterbar_FOUND AND NOT TARGET LibtorrentRasterbar::torrent-rasterbar) + add_library(LibtorrentRasterbar::torrent-rasterbar SHARED IMPORTED) + + # LibtorrentRasterbar_DEFINITIONS var contains a mix of -D, -f, and possible -std options + # let's split them into definitions and options (that are not definitions) + set(LibtorrentRasterbar_defines "${LibtorrentRasterbar_DEFINITIONS}") + set(LibtorrentRasterbar_options "${LibtorrentRasterbar_DEFINITIONS}") + list(FILTER LibtorrentRasterbar_defines INCLUDE REGEX "(^|;)-D.+") + list(FILTER LibtorrentRasterbar_options EXCLUDE REGEX "(^|;)-D.+") + # remove '-D' from LibtorrentRasterbar_defines + string(REGEX REPLACE "(^|;)(-D)" "\\1" LibtorrentRasterbar_defines "${LibtorrentRasterbar_defines}") + + set_target_properties(LibtorrentRasterbar::torrent-rasterbar PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "CXX" + IMPORTED_LOCATION "${LibtorrentRasterbar_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${LibtorrentRasterbar_INCLUDE_DIRS}" + INTERFACE_SYSTEM_INCLUDE_DIRECTORIES "${LibtorrentRasterbar_INCLUDE_DIRS}" + INTERFACE_LINK_LIBRARIES "${LibtorrentRasterbar_LIBRARIES}" + INTERFACE_COMPILE_DEFINITIONS "${LibtorrentRasterbar_defines}" + INTERFACE_COMPILE_OPTIONS "${LibtorrentRasterbar_options}" + ) + endif() endif() - -message(STATUS "libtorrent definitions: ${LibtorrentRasterbar_DEFINITIONS}") - -find_path(LibtorrentRasterbar_INCLUDE_DIR libtorrent - HINTS ${PC_LIBTORRENT_RASTERBAR_INCLUDEDIR} ${PC_LIBTORRENT_RASTERBAR_INCLUDE_DIRS} - PATH_SUFFIXES libtorrent-rasterbar) - -find_library(LibtorrentRasterbar_LIBRARY NAMES torrent-rasterbar - HINTS ${PC_LIBTORRENT_RASTERBAR_LIBDIR} ${PC_LIBTORRENT_RASTERBAR_LIBRARY_DIRS}) - -if(LibtorrentRasterbar_USE_STATIC_LIBS) - set(CMAKE_FIND_LIBRARY_SUFFIXES ${LibtorrentRasterbar_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES}) -endif() - -set(LibtorrentRasterbar_LIBRARIES ${LibtorrentRasterbar_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) -set(LibtorrentRasterbar_INCLUDE_DIRS ${LibtorrentRasterbar_INCLUDE_DIR}) - -if(NOT Boost_SYSTEM_FOUND OR NOT Boost_CHRONO_FOUND OR NOT Boost_RANDOM_FOUND) - find_package(Boost REQUIRED COMPONENTS system chrono random) - set(LibtorrentRasterbar_LIBRARIES - ${LibtorrentRasterbar_LIBRARIES} ${Boost_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT}) - set(LibtorrentRasterbar_INCLUDE_DIRS - ${LibtorrentRasterbar_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS}) -endif() - -list(FIND LibtorrentRasterbar_DEFINITIONS -DTORRENT_USE_OPENSSL LibtorrentRasterbar_ENCRYPTION_INDEX) -if(LibtorrentRasterbar_ENCRYPTION_INDEX GREATER -1) - find_package(OpenSSL REQUIRED) - set(LibtorrentRasterbar_LIBRARIES ${LibtorrentRasterbar_LIBRARIES} ${OPENSSL_LIBRARIES}) - set(LibtorrentRasterbar_INCLUDE_DIRS ${LibtorrentRasterbar_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIRS}) - set(LibtorrentRasterbar_OPENSSL_ENABLED ON) -endif() - -include(FindPackageHandleStandardArgs) -# handle the QUIETLY and REQUIRED arguments and set LibtorrentRasterbar_FOUND to TRUE -# if all listed variables are TRUE -find_package_handle_standard_args(LibtorrentRasterbar DEFAULT_MSG - LibtorrentRasterbar_LIBRARY - LibtorrentRasterbar_INCLUDE_DIR - Boost_SYSTEM_FOUND - Boost_CHRONO_FOUND - Boost_RANDOM_FOUND) - -mark_as_advanced(LibtorrentRasterbar_INCLUDE_DIR LibtorrentRasterbar_LIBRARY - LibtorrentRasterbar_ORIG_CMAKE_FIND_LIBRARY_SUFFIXES - LibtorrentRasterbar_ENCRYPTION_INDEX) diff --git a/libtorrent-rasterbar-cmake.pc.in b/libtorrent-rasterbar-cmake.pc.in deleted file mode 100644 index ee5f51943..000000000 --- a/libtorrent-rasterbar-cmake.pc.in +++ /dev/null @@ -1,6 +0,0 @@ -Name: libtorrent-rasterbar -Description: Bittorrent library. -Version: @VERSION@ -Libs: -L${CMAKE_INSTALL_PREFIX}/lib -ltorrent-rasterbar -Cflags: -I${CMAKE_INSTALL_PREFIX}/include -I${CMAKE_INSTALL_PREFIX}/include/libtorrent @COMPILETIME_OPTIONS@ @CXX_DEFINES@ - diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 182e200ae..6dcbb68f2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,29 +1,22 @@ -cmake_minimum_required(VERSION 2.6) file(GLOB tests "${CMAKE_CURRENT_SOURCE_DIR}/test_*.cpp") list(REMOVE_ITEM tests "${CMAKE_CURRENT_SOURCE_DIR}/test_natpmp.cpp") # doesn't build at time of writing list(REMOVE_ITEM tests "${CMAKE_CURRENT_SOURCE_DIR}/test_utils.cpp") # helper file, not a test -add_library(test_common OBJECT main.cpp test.cpp setup_transfer.cpp dht_server.cpp udp_tracker.cpp +add_library(test_common STATIC main.cpp test.cpp setup_transfer.cpp dht_server.cpp udp_tracker.cpp peer_server.cpp web_seed_suite.cpp swarm_suite.cpp test_utils.cpp make_torrent.cpp settings.cpp ) -target_compile_definitions(test_common PRIVATE $) - -if(MSVC) - set_property(TARGET test_common PROPERTY COMPILE_PDB_NAME "${CMAKE_CURRENT_BINARY_DIR}/test_common") -endif() +target_link_libraries(test_common PUBLIC torrent-rasterbar) foreach(TARGET_SRC ${tests}) get_filename_component(TARGET ${TARGET_SRC} NAME_WE) - add_executable(${TARGET} ${TARGET_SRC} $) - target_link_libraries(${TARGET} torrent-rasterbar) + add_executable(${TARGET} ${TARGET_SRC}) + target_link_libraries(${TARGET} test_common) add_test(${TARGET} ${TARGET}) endforeach() -if (deprecated-functions) - add_executable(bdecode_benchmark bdecode_benchmark.cpp) - target_link_libraries(bdecode_benchmark torrent-rasterbar) -endif() +add_executable(bdecode_benchmark bdecode_benchmark.cpp) +target_link_libraries(bdecode_benchmark torrent-rasterbar) file(GLOB GZIP_ASSETS "${CMAKE_CURRENT_SOURCE_DIR}/*.gz") file(COPY ${GZIP_ASSETS} DESTINATION "${CMAKE_CURRENT_BINARY_DIR}") diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt new file mode 100644 index 000000000..484803316 --- /dev/null +++ b/tools/CMakeLists.txt @@ -0,0 +1,5 @@ +add_executable(dht dht_put.cpp) +target_link_libraries(dht PRIVATE torrent-rasterbar) + +add_executable(parse_access_log parse_access_log.cpp) +target_link_libraries(parse_access_log PRIVATE torrent-rasterbar)