diff --git a/CMakeLists.txt b/CMakeLists.txt index 025203badf..a631292261 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,12 @@ else() message("-- INFO: Using VCPKG if detected") endif() +if (DPP_NO_CONAN) + message("-- INFO: Explicitly disabling Conan as running inside the CI action.") +else() + message("-- INFO: Using Conan if detected") +endif() + if (WIN32 AND NOT MINGW AND BUILD_SHARED_LIBS) message("-- INFO: Configuring .rc resource script") configure_file("${DPP_ROOT_PATH}/src/dpp/dpp.rc.in" "${DPP_ROOT_PATH}/src/dpp/dpp.rc" NEWLINE_STYLE WIN32) @@ -99,7 +105,11 @@ else() enable_testing(${CMAKE_CURRENT_SOURCE_DIR}) endif() - add_subdirectory(library) + if(CONAN_EXPORTED AND NOT DPP_NO_CONAN) + add_subdirectory(library-conan) + else() + add_subdirectory(library) + endif() endif() if(DPP_USE_EXTERNAL_JSON) diff --git a/library-conan/CMakeLists.txt b/library-conan/CMakeLists.txt new file mode 100644 index 0000000000..5e5894c656 --- /dev/null +++ b/library-conan/CMakeLists.txt @@ -0,0 +1,315 @@ +message("-- INFO: Conan detected... finding packages") +find_package(OpenSSL REQUIRED COMPONENTS SSL Crypto) +find_package(ZLIB REQUIRED) +find_package(libsodium REQUIRED) +find_package(Opus) +find_package(Threads REQUIRED) +find_package(Git QUIET) + +# Check for various C functions + +check_cxx_symbol_exists(prctl "sys/prctl.h" HAVE_PRCTL) +check_cxx_symbol_exists(pthread_setname_np "pthread.h" HAVE_PTHREAD_SETNAME_NP) + +# Go into more detail here and identify the valid signature of pthread_setname_np, +# because different systems have different forms of this function (ugh). +if (HAVE_PTHREAD_SETNAME_NP) + include(CheckCXXSourceCompiles) + check_cxx_source_compiles(" + #include + int main() { + pthread_setname_np(\"ThreadName\"); + return 0; + }" HAVE_SINGLE_PARAMETER_SETNAME_NP) + check_cxx_source_compiles(" + #include + int main() { + pthread_setname_np(pthread_self(), \"ThreadName\"); + return 0; + }" HAVE_TWO_PARAMETER_SETNAME_NP) +endif() + +add_compile_definitions(DPP_OS=${CMAKE_SYSTEM_NAME}) + +if(${AVX_TYPE} STREQUAL "OFF") + include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/DetectArchitecture.cmake") +else() + message("-- AVX type overridden by configuration: ${AVX_TYPE}") +endif() +STRING(REPLACE "AVX" "" AVX_TYPE ${AVX_TYPE}) +add_compile_definitions(AVX_TYPE=${AVX_TYPE}) +add_compile_options(${AVX_FLAG}) + +if(WIN32 AND NOT MINGW) + if (NOT WINDOWS_32_BIT) + message("-- Setting Windows flags") + add_compile_definitions(_WINSOCK_DEPRECATED_NO_WARNINGS) + add_compile_definitions(WIN32_LEAN_AND_MEAN) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS) + add_compile_definitions(_CRT_NONSTDC_NO_DEPRECATE) + endif() +endif() + +if (UNIX) + message("-- Checking for ability to update autogenerated files") + execute_process( + COMMAND which php + RESULT_VARIABLE HAS_PHP + OUTPUT_QUIET + ) + + if (${HAS_PHP} STREQUAL "0") + message("-- Checking for update to autogenerated files") + # target for rebuild of cluster::*_sync() functions + execute_process( + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.." + COMMAND php buildtools/make_struct.php "\\Dpp\\Generator\\SyncGenerator" + ) + set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/../include/dpp/cluster_sync_calls.h" PROPERTIES GENERATED TRUE ) + # target for unicode_emojis.h + execute_process( + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.." + COMMAND php buildtools/emojis.php + ) + set_source_files_properties( "${CMAKE_CURRENT_SOURCE_DIR}/../include/dpp/unicode_emojis.h" PROPERTIES GENERATED TRUE ) + else() + message("-- Autogeneration is not available") + endif() +endif() + +include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/colour.cmake") + if (BUILD_VOICE_SUPPORT) + if(Opus_FOUND AND libsodium_FOUND) + message("-- Found Opus ${Green}${Opus_VERSION}${ColourReset}") + add_compile_definitions(HAVE_VOICE) + message("-- Sodium ${Green}${libsodium_VERSION}${ColourReset}") + set(HAVE_VOICE 1) + endif() + + if(HAVE_VOICE) + message("-- Detected ${Green}libsodium${ColourReset} and ${Green}libopus${ColourReset}. VOICE support will be ${Green}enabled${ColourReset}") + else(HAVE_VOICE) + message("-- Could not detect ${Green}libsodium${ColourReset} and/or ${Green}libopus${ColourReset}. VOICE support will be ${Red}disabled${ColourReset}") + endif(HAVE_VOICE) + else() + message("-- Voice support disabled by cmake option") + endif() + +string(ASCII 27 Esc) + +set(THREADS_PREFER_PTHREAD_FLAG ON) + +if(NOT GIT_FOUND AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../.git") + message(FATAL_ERROR "You are using a git version of D++ but do not have git installed. Install git (not 'gh') and try again.") +endif() + +if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/../.git") + message("-- Building ${Green}git${ColourReset} version. ${Green}Be aware git versions may be unstable!${ColourReset}") +else() + message("-- Building ${Green}stable${ColourReset} version ${Green}${DPP_VERSION}${ColourReset}") +endif() + +if(UNIX OR MSYS) + find_program(LDCONFIG_EXECUTABLE "ldconfig") +endif() + +if(MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /sdl /DFD_SETSIZE=1024") + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /Od /DEBUG /Zi") + else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /O2 /Oi /Oy /Gy") + endif() + if(NOT DPP_CLANG_CL) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /MP /Zc:preprocessor") + if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /GL") + endif() + endif() + string(REGEX REPLACE "/W[1|2|3|4]" "/W3" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") +else() + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-unused-private-field -Wno-psabi -Wempty-body -Wignored-qualifiers -Wimplicit-fallthrough -Wmissing-field-initializers -Wsign-compare -Wtype-limits -Wuninitialized -Wshift-negative-value -pthread") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -Og") + + if (NOT MINGW) + add_link_options("-rdynamic") + endif () +endif() + +set(modules_dir "../src") + +file(GLOB subdirlist ${modules_dir}/dpp) + +foreach (fullmodname ${subdirlist}) + get_filename_component(modname ${fullmodname} NAME) + set (modsrc "") + + file(GLOB modsrc "${modules_dir}/dpp/*.cpp" "${modules_dir}/dpp/events/*.cpp" "${modules_dir}/dpp/cluster/*.cpp" "${modules_dir}/dpp/*.rc") + + if(BUILD_SHARED_LIBS) + add_library(${modname} SHARED ${modsrc}) + else() + add_library(${modname} STATIC ${modsrc}) + endif() + set_target_properties(${modname} + PROPERTIES + VERSION ${CMAKE_PROJECT_VERSION} + SOVERSION ${CMAKE_PROJECT_VERSION} + POSITION_INDEPENDENT_CODE true + ) + target_include_directories(${modname} PUBLIC + $ + $ + ) + + if (DPP_USE_PCH) + target_precompile_headers(${modname} PRIVATE + "${CMAKE_CURRENT_SOURCE_DIR}/../include/dpp/cluster.h" + "${CMAKE_CURRENT_SOURCE_DIR}/../include/dpp/json.h" + "${CMAKE_CURRENT_SOURCE_DIR}/../include/dpp/utility.h" + "${CMAKE_CURRENT_SOURCE_DIR}/../include/dpp/restresults.h" + ) + endif() + + if (WIN32 AND NOT MINGW) + target_link_libraries(${modname} PRIVATE openssl::openssl + libsodium::libsodium + Opus::opus + ZLIB::ZLIB) + else() + target_link_libraries(${modname} PRIVATE openssl::openssl ZLIB::ZLIB) + if (MINGW) + target_link_libraries(${modname} PUBLIC wsock32 ws2_32 crypt32) + endif () + endif() + + if (HAVE_VOICE) + target_link_libraries(${modname} PRIVATE libsodium::libsodium Opus::opus) + include_directories(${OPUS_INCLUDE_DIRS} ${sodium_INCLUDE_DIR}) + endif() + +endforeach() + +target_compile_features(dpp PUBLIC cxx_std_17) +target_compile_features(dpp PRIVATE cxx_constexpr) +target_compile_features(dpp PRIVATE cxx_auto_type) +target_compile_features(dpp PRIVATE cxx_defaulted_functions) +target_compile_features(dpp PRIVATE cxx_deleted_functions) +target_compile_features(dpp PRIVATE cxx_final) +target_compile_features(dpp PRIVATE cxx_lambdas) +target_compile_features(dpp PRIVATE cxx_override) +target_compile_features(dpp PRIVATE cxx_thread_local) +target_compile_features(dpp PRIVATE cxx_variadic_templates) +target_compile_features(dpp PRIVATE cxx_attribute_deprecated) + +if(HAVE_PRCTL) + target_compile_definitions(dpp PRIVATE HAVE_PRCTL) +endif() +if(HAVE_PTHREAD_SETNAME_NP) + target_compile_definitions(dpp PRIVATE HAVE_PTHREAD_SETNAME_NP) +endif() + +if(DPP_CORO) + message("-- ${Yellow}Enabled experimental coroutine feature${ColourReset}") + set(CMAKE_CXX_STANDARD 20) + target_compile_features(dpp PUBLIC cxx_std_20) + if(WIN32 AND NOT MINGW AND NOT DPP_CLANG_CL) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /await:strict") # https://learn.microsoft.com/en-us/cpp/build/reference/await-enable-coroutine-support?view=msvc-170 + else() + if(CMAKE_CXX_COMPILER_ID MATCHES "Clang") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 14.0.0) # clang >= 14 has native support + message("-- ${Yellow}Clang < 14 - attempting to detect if using libc++ or stdc++${ColourReset}") + check_cxx_source_compiles(" + #include + + int a = + #ifdef __GLIBCXX__ + 1; + #else + fgsfds; + #endif + + int main(int argc, char* argv[]) + { + return 0; + } + " IS_GLIBCXX) + if(IS_GLIBCXX) + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.0.0) + message(FATAL_ERROR "${BoldRed}Clang with stdc++ and coroutines requires version 12.0.0 or above${ColourReset}") + endif() + message("-- ${Yellow}Detected stdc++ - enabling mock std::experimental namespace${ColourReset}") + target_compile_definitions(dpp PUBLIC "STDCORO_GLIBCXX_COMPAT") + else() + message("-- ${Yellow}Detected libc++ - using ${ColourReset}") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9.0.0) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcoroutines-ts") + endif() + endif() + message("-- ${Yellow}Note - coroutines in clang < 14 are experimental, upgrading is recommended${ColourReset}") + endif() + elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 10.0) + message(FATAL_ERROR "${BoldRed}Coroutines with g++ require version 10 or above${ColourReset}") + elseif(CMAKE_CXX_COMPILER_VERSION VERSION_LESS 11.0) + message("-- ${Yellow}Note - coroutines in g++10 are experimental, upgrading to g++11 or above is recommended${ColourReset}") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fcoroutines") + endif() + endif() + endif() + target_compile_definitions(dpp PUBLIC DPP_CORO) + execute_process(WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/.." + COMMAND php buildtools/make_struct.php "\\Dpp\\Generator\\CoroGenerator") +endif() + +if (DPP_BUILD_TEST) + enable_testing(${CMAKE_CURRENT_SOURCE_DIR}/..) + file(GLOB testnamelist "${CMAKE_CURRENT_SOURCE_DIR}/../src/*") + foreach (fulltestname ${testnamelist}) + get_filename_component(testname ${fulltestname} NAME) + if (NOT "${testname}" STREQUAL "dpp") + message("-- Configuring test: ${Green}${testname}${ColourReset} with source: ${modules_dir}/${testname}/*.cpp") + set (testsrc "") + file(GLOB testsrc "${modules_dir}/${testname}/*.cpp") + add_executable(${testname} ${testsrc}) + if (DPP_CORO) + target_compile_features(${testname} PRIVATE cxx_std_20) + else() + target_compile_features(${testname} PRIVATE cxx_std_17) + endif() + if (MSVC) + target_compile_options(${testname} PRIVATE /utf-8) + endif() + target_link_libraries(${testname} PUBLIC ${modname}) + endif() + endforeach() + add_test( + NAME unittest + COMMAND unittest + ) +endif() + +if(DPP_INSTALL) + if(NOT WIN32) + # Installation + + include(GNUInstallDirs) + install(TARGETS dpp LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) + message("Library install directory at ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") + install(DIRECTORY ../include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + message("Include files install directory at ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}") + install(CODE "execute_process(COMMAND ${CMAKE_COMMAND} -DRUN_LDCONFIG=${RUN_LDCONFIG} -DLDCONFIG_EXECUTABLE=${LDCONFIG_EXECUTABLE} -P ${CMAKE_CURRENT_SOURCE_DIR}/../cmake/PostInstall.cmake)") + + configure_file("${CMAKE_CURRENT_SOURCE_DIR}/../dpp.pc.in" "${CMAKE_BINARY_DIR}/dpp.pc" @ONLY) + install(FILES "${CMAKE_BINARY_DIR}/dpp.pc" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + elseif(MINGW) + install(TARGETS dpp LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib) + install(DIRECTORY ../include/ DESTINATION ${CMAKE_INSTALL_PREFIX}/include) + endif() + + # Setup information for packaging and distribution + include("${CMAKE_CURRENT_SOURCE_DIR}/../cmake/CPackSetup.cmake") + + # CPack initialization for distribution + include(CPack) +endif() diff --git a/library-conan/conanfile.py b/library-conan/conanfile.py new file mode 100644 index 0000000000..d267f45c10 --- /dev/null +++ b/library-conan/conanfile.py @@ -0,0 +1,69 @@ +import os +from conan import ConanFile +from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout, CMakeDeps +from conan.tools.scm import Git +from conan.tools.files import update_conandata + +class DPPConan(ConanFile): + name = "dpp" + version = "10.0.29" + default_user = "brainboxdotcc" + default_channel = "testing" + license = "https://github.com/brainboxdotcc/DPP/blob/master/LICENSE" + url = "https://github.com/brainboxdotcc/DPP" + description = "D++ is a lightweight and efficient library for Discord" + topics = ("discord") + settings = "os", "compiler", "build_type", "arch" + options = {"shared": [True, False], "fPIC": [True, False]} + default_options = {"shared": False, "fPIC": True} + + def requirements(self): + self.requires("nlohmann_json/3.11.2") + self.requires("openssl/3.1.2") + self.requires("zlib/1.3") + self.requires("libsodium/cci.20220430") + self.requires("opus/1.4") + + def config_options(self): + if self.settings.os == "Windows": + self.options.rm_safe("fPIC") + + def configure(self): + if self.options.shared: + self.options.rm_safe("fPIC") + + def layout(self): + cmake_layout(self) + + def export(self): + git = Git(self, os.path.dirname(self.recipe_folder)) + scm_url, scm_commit = git.get_url_and_commit() + update_conandata(self, {"sources": {"commit": scm_commit, "url": scm_url}}) + + def source(self): + git = Git(self) + sources = self.conan_data["sources"] + git.clone(url=sources["url"], target=".") + git.checkout(commit=sources["commit"]) + + def generate(self): + deps = CMakeDeps(self) + deps.generate() + tc = CMakeToolchain(self) + tc.cache_variables["CONAN_EXPORTED"] = True + tc.cache_variables["BUILD_VOICE_SUPPORT"] = True + tc.cache_variables["DPP_BUILD_TEST"] = False + tc.cache_variables["BUILD_SHARED_LIBS"] = False + tc.generate() + + def build(self): + cmake = CMake(self) + cmake.configure() + cmake.build() + + def package(self): + cmake = CMake(self) + cmake.install() + + def package_info(self): + self.cpp_info.libs = ["dpp"] \ No newline at end of file