diff --git a/Async++Config.cmake.in b/Async++Config.cmake.in index ade2b3e..e7ba32b 100644 --- a/Async++Config.cmake.in +++ b/Async++Config.cmake.in @@ -1,3 +1,3 @@ include(CMakeFindDependencyMacro) find_dependency(Threads) -include("${CMAKE_CURRENT_LIST_DIR}/Async++.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/asyncxx-targets.cmake") diff --git a/CMakeLists.txt b/CMakeLists.txt index bb2de4d..8b63400 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,17 +21,21 @@ cmake_minimum_required(VERSION 3.1) project(Async++ C CXX) -option(BUILD_SHARED_LIBS "Build Async++ as a shared library" ON) +option(ASYNCXX_BUILD_SHARED "Build shared library" ON) +option(ASYNCXX_BUILD_STATIC "Build static library" OFF) option(USE_CXX_EXCEPTIONS "Enable C++ exception support" ON) if (APPLE) option(BUILD_FRAMEWORK "Build a Mac OS X framework instead of a library" OFF) - if (BUILD_FRAMEWORK AND NOT BUILD_SHARED_LIBS) + if (BUILD_FRAMEWORK AND NOT ASYNCXX_BUILD_SHARED) message(FATAL_ERROR "Can't build a framework with static libraries") endif() endif() set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +set(ASYNCXX_SHARED_LIBRARY async++) +set(ASYNCXX_STATIC_LIBRARY async++-static) + # Add all source and header files so IDEs can see them set(ASYNCXX_INCLUDE ${PROJECT_SOURCE_DIR}/include/async++/aligned_alloc.h @@ -61,59 +65,124 @@ set(ASYNCXX_SRC ) source_group(include FILES ${PROJECT_SOURCE_DIR}/include/async++.h ${ASYNCXX_INCLUDE}) source_group(src FILES ${ASYNCXX_SRC}) -add_library(Async++ ${PROJECT_SOURCE_DIR}/include/async++.h ${ASYNCXX_INCLUDE} ${ASYNCXX_SRC}) -# Async++ only depends on the C++11 standard libraries, but some implementations -# require the -pthread compiler flag to enable threading functionality. -if (NOT MSVC) - target_compile_options(Async++ PRIVATE -std=c++11) +if(${ASYNCXX_BUILD_SHARED}) + list(APPEND ASYNCXX_TARGETS ${ASYNCXX_SHARED_LIBRARY}) endif() -if (APPLE) - # Use libc++ on Mac because the shipped libstdc++ version is ancient - target_compile_options(Async++ PRIVATE -stdlib=libc++) - set_target_properties(Async++ PROPERTIES LINK_FLAGS -stdlib=libc++) + +if(${ASYNCXX_BUILD_STATIC}) + list(APPEND ASYNCXX_TARGETS ${ASYNCXX_STATIC_LIBRARY}) +endif() + +if(NOT ASYNCXX_TARGETS) + message(FATAL_ERROR "No targets are specified") endif() + set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(Threads REQUIRED) -target_link_libraries(Async++ PUBLIC Threads::Threads) -# Set up preprocessor definitions -target_include_directories(Async++ PRIVATE ${PROJECT_SOURCE_DIR}/include) -set_target_properties(Async++ PROPERTIES DEFINE_SYMBOL LIBASYNC_BUILD) -if (BUILD_SHARED_LIBS) - # Minimize the set of symbols exported by libraries - set_target_properties(Async++ PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON) -else() - target_compile_definitions(Async++ PUBLIC LIBASYNC_STATIC) -endif() +if(${ASYNCXX_BUILD_SHARED}) + message(STATUS "Creating shared library: ${ASYNCXX_SHARED_LIBRARY}") + add_library(${ASYNCXX_SHARED_LIBRARY} SHARED ${PROJECT_SOURCE_DIR}/include/async++.h ${ASYNCXX_INCLUDE} ${ASYNCXX_SRC}) + target_compile_features(${ASYNCXX_SHARED_LIBRARY} PUBLIC cxx_std_14) +# Async++ only depends on the C++11 standard libraries, but some implementations +# require the -pthread compiler flag to enable threading functionality. + if (NOT MSVC) + target_compile_options(${ASYNCXX_SHARED_LIBRARY} PRIVATE -std=c++11) + endif() + if (APPLE) + # Use libc++ on Mac because the shipped libstdc++ version is ancient + target_compile_options(${ASYNCXX_SHARED_LIBRARY} PRIVATE -stdlib=libc++) + set_target_properties(${ASYNCXX_SHARED_LIBRARY} PROPERTIES LINK_FLAGS -stdlib=libc++) + endif() + target_link_libraries(${ASYNCXX_SHARED_LIBRARY} PUBLIC Threads::Threads) +# Set up preprocessor definitions + target_include_directories(${ASYNCXX_SHARED_LIBRARY} PRIVATE ${PROJECT_SOURCE_DIR}/include) + set_target_properties(${ASYNCXX_SHARED_LIBRARY} PROPERTIES DEFINE_SYMBOL LIBASYNC_BUILD) + set_target_properties(${ASYNCXX_SHARED_LIBRARY} PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON) # Enable warnings for strict C++ standard conformance -if (NOT MSVC) - target_compile_options(Async++ PRIVATE -Wall -Wextra -pedantic) -endif() - + if (NOT MSVC) + target_compile_options(${ASYNCXX_SHARED_LIBRARY} PRIVATE -Wall -Wextra -pedantic) + endif() # Async++ doesn't make use of RTTI information, so don't generate it. # There are issues on Apple platforms with exceptions and -fno-rtti, so keep it # enabled there. # See https://stackoverflow.com/questions/21737201/problems-throwing-and-catching-exceptions-on-os-x-with-fno-rtti -if (MSVC) - target_compile_options(Async++ PRIVATE /GR-) -elseif(NOT APPLE) - target_compile_options(Async++ PRIVATE -fno-rtti) -endif() - -# Allow disabling exceptions, but warn the user about the consequences -if (NOT USE_CXX_EXCEPTIONS) - message(WARNING "Exceptions have been disabled. Any operation that would " - "throw an exception will result in a call to std::abort() instead.") - target_compile_definitions(Async++ PUBLIC LIBASYNC_NO_EXCEPTIONS) if (MSVC) - target_compile_options(Async++ PUBLIC /EHs-c-) - else() - target_compile_options(Async++ PUBLIC -fno-exceptions) + target_compile_options(${ASYNCXX_SHARED_LIBRARY} PRIVATE /GR-) + elseif(NOT APPLE) + target_compile_options(${ASYNCXX_SHARED_LIBRARY} PRIVATE -fno-rtti) endif() +# Allow disabling exceptions, but warn the user about the consequences + if (NOT USE_CXX_EXCEPTIONS) + message(WARNING "Exceptions have been disabled. Any operation that would " + "throw an exception will result in a call to std::abort() instead.") + target_compile_definitions(${ASYNCXX_SHARED_LIBRARY} PUBLIC LIBASYNC_NO_EXCEPTIONS) + if (MSVC) + target_compile_options(${ASYNCXX_SHARED_LIBRARY} PUBLIC /EHs-c-) + else() + target_compile_options(${ASYNCXX_SHARED_LIBRARY} PUBLIC -fno-exceptions) + endif() + endif() +# /Zc:__cplusplus is required to make __cplusplus accurate +# /Zc:__cplusplus is available starting with Visual Studio 2017 version 15.7 +# (according to https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus) +# That version is equivalent to _MSC_VER==1914 +# (according to https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=vs-2019) +# CMake's ${MSVC_VERSION} is equivalent to _MSC_VER +# (according to https://cmake.org/cmake/help/latest/variable/MSVC_VERSION.html#variable:MSVC_VERSION) +# GREATER and EQUAL are used because GREATER_EQUAL is available starting with CMake 3.7 +# (according to https://cmake.org/cmake/help/v3.7/release/3.7.html#commands) + if ((MSVC) AND ((MSVC_VERSION GREATER 1914) OR (MSVC_VERSION EQUAL 1914))) + target_compile_options(${ASYNCXX_SHARED_LIBRARY} PUBLIC /Zc:__cplusplus) + endif() + list(APPEND TARGET_FILES ${ASYNCXX_SHARED_LIBRARY}) endif() +if(${ASYNCXX_BUILD_STATIC}) + message(STATUS "Creating static library: ${ASYNCXX_STATIC_LIBRARY}") + add_library(${ASYNCXX_STATIC_LIBRARY} STATIC ${PROJECT_SOURCE_DIR}/include/async++.h ${ASYNCXX_INCLUDE} ${ASYNCXX_SRC}) + target_compile_features(${ASYNCXX_STATIC_LIBRARY} PUBLIC cxx_std_14) +# Async++ only depends on the C++11 standard libraries, but some implementations +# require the -pthread compiler flag to enable threading functionality. + if (NOT MSVC) + target_compile_options(${ASYNCXX_STATIC_LIBRARY} PRIVATE -std=c++11) + endif() + if (APPLE) + # Use libc++ on Mac because the shipped libstdc++ version is ancient + target_compile_options(${ASYNCXX_STATIC_LIBRARY} PRIVATE -stdlib=libc++) + set_target_properties(${ASYNCXX_STATIC_LIBRARY} PROPERTIES LINK_FLAGS -stdlib=libc++) + endif() + target_link_libraries(${ASYNCXX_STATIC_LIBRARY} PUBLIC Threads::Threads) +# Set up preprocessor definitions + target_include_directories(${ASYNCXX_STATIC_LIBRARY} PRIVATE ${PROJECT_SOURCE_DIR}/include) + set_target_properties(${ASYNCXX_STATIC_LIBRARY} PROPERTIES DEFINE_SYMBOL LIBASYNC_BUILD) + target_compile_definitions(${ASYNCXX_STATIC_LIBRARY} PUBLIC LIBASYNC_STATIC) +# Enable warnings for strict C++ standard conformance + if (NOT MSVC) + target_compile_options(${ASYNCXX_STATIC_LIBRARY} PRIVATE -Wall -Wextra -pedantic) + endif() +# Async++ doesn't make use of RTTI information, so don't generate it. +# There are issues on Apple platforms with exceptions and -fno-rtti, so keep it +# enabled there. +# See https://stackoverflow.com/questions/21737201/problems-throwing-and-catching-exceptions-on-os-x-with-fno-rtti + if (MSVC) + target_compile_options(${ASYNCXX_STATIC_LIBRARY} PRIVATE /GR-) + elseif(NOT APPLE) + target_compile_options(${ASYNCXX_STATIC_LIBRARY} PRIVATE -fno-rtti) + endif() +# Allow disabling exceptions, but warn the user about the consequences + if (NOT USE_CXX_EXCEPTIONS) + message(WARNING "Exceptions have been disabled. Any operation that would " + "throw an exception will result in a call to std::abort() instead.") + target_compile_definitions(${ASYNCXX_STATIC_LIBRARY} PUBLIC LIBASYNC_NO_EXCEPTIONS) + if (MSVC) + target_compile_options(${ASYNCXX_STATIC_LIBRARY} PUBLIC /EHs-c-) + else() + target_compile_options(${ASYNCXX_STATIC_LIBRARY} PUBLIC -fno-exceptions) + endif() + endif() # /Zc:__cplusplus is required to make __cplusplus accurate # /Zc:__cplusplus is available starting with Visual Studio 2017 version 15.7 # (according to https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus) @@ -123,10 +192,20 @@ endif() # (according to https://cmake.org/cmake/help/latest/variable/MSVC_VERSION.html#variable:MSVC_VERSION) # GREATER and EQUAL are used because GREATER_EQUAL is available starting with CMake 3.7 # (according to https://cmake.org/cmake/help/v3.7/release/3.7.html#commands) -if ((MSVC) AND ((MSVC_VERSION GREATER 1914) OR (MSVC_VERSION EQUAL 1914))) - target_compile_options(Async++ PUBLIC /Zc:__cplusplus) + if ((MSVC) AND ((MSVC_VERSION GREATER 1914) OR (MSVC_VERSION EQUAL 1914))) + target_compile_options(${ASYNCXX_STATIC_LIBRARY} PUBLIC /Zc:__cplusplus) + endif() +# In *nix systems, the static library can have the same base filename +# In Windows they need different names + if(UNIX) + set_target_properties(${ASYNCXX_STATIC_LIBRARY} PROPERTIES + OUTPUT_NAME ${ASYNCXX_SHARED_LIBRARY} + ) + endif() + list(APPEND TARGET_FILES ${ASYNCXX_STATIC_LIBRARY}) endif() +# Produce find_package helper config file include(CMakePackageConfigHelpers) configure_package_config_file("${CMAKE_CURRENT_LIST_DIR}/Async++Config.cmake.in" "${PROJECT_BINARY_DIR}/Async++Config.cmake" @@ -139,22 +218,26 @@ install(FILES "${PROJECT_BINARY_DIR}/Async++Config.cmake" # Install the library and produce a CMake export script include(GNUInstallDirs) -install(TARGETS Async++ - EXPORT Async++ +install(TARGETS ${TARGET_FILES} + EXPORT asyncxx-targets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} FRAMEWORK DESTINATION Frameworks ) -export(EXPORT Async++) -install(EXPORT Async++ DESTINATION cmake) +export(EXPORT asyncxx-targets) +install(EXPORT asyncxx-targets DESTINATION cmake) if (APPLE AND BUILD_FRAMEWORK) - set_target_properties(Async++ PROPERTIES OUTPUT_NAME Async++ FRAMEWORK ON) + set_target_properties(${ASYNCXX_SHARED_LIBRARY} PROPERTIES OUTPUT_NAME Async++ FRAMEWORK ON) set_source_files_properties(${ASYNCXX_INCLUDE} PROPERTIES MACOSX_PACKAGE_LOCATION Headers/async++) set_source_files_properties(${PROJECT_SOURCE_DIR}/include/async++.h PROPERTIES MACOSX_PACKAGE_LOCATION Headers) else() - set_target_properties(Async++ PROPERTIES OUTPUT_NAME async++) - target_include_directories(Async++ INTERFACE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>) + if(${ASYNCXX_BUILD_SHARED}) + target_include_directories(${ASYNCXX_SHARED_LIBRARY} INTERFACE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>) + endif() + if(${ASYNCXX_BUILD_STATIC}) + target_include_directories(${ASYNCXX_STATIC_LIBRARY} INTERFACE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include> $<INSTALL_INTERFACE:include>) + endif() install(FILES ${PROJECT_SOURCE_DIR}/include/async++.h DESTINATION include) install(FILES ${ASYNCXX_INCLUDE} DESTINATION include/async++) endif() diff --git a/README.md b/README.md index d19ce24..e701eb1 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ Supported Platforms The only requirement to use Async++ is a C++11 compiler and standard library. Unfortunately C++11 is not yet fully implemented on most platforms. Here is the list of OS and compiler combinations which are known to work. - Linux: Works with GCC 4.7+, Clang 3.2+ and Intel compiler 15+. +- FreeBSD 13+: Works with Clang from base system. - Mac: Works with Apple Clang (using libc++). GCC also works but you must get a recent version (4.7+). - iOS: Works with Apple Clang (using libc++). Note: because iOS has no thread local support, the library uses a workaround based on pthreads. - Windows: Works with GCC 4.8+ (with pthread-win32) and Visual Studio 2013+.