diff --git a/CMakeLists.txt b/CMakeLists.txt index f50c96c04..f056faa7c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -95,6 +95,7 @@ option(SPDLOG_BUILD_WARNINGS "Enable compiler warnings" OFF) # install options option(SPDLOG_SYSTEM_INCLUDES "Include as system headers (skip for clang-tidy)." OFF) option(SPDLOG_INSTALL "Generate the install target" ${SPDLOG_MASTER_PROJECT}) +option(SPDLOG_GENERATE_TWEAKME_H "Generate tweakme.h from the CMake configuration" OFF) option(SPDLOG_USE_STD_FORMAT "Use std::format instead of fmt library." OFF) option(SPDLOG_FMT_EXTERNAL "Use external fmt library instead of bundled" OFF) option(SPDLOG_FMT_EXTERNAL_HO "Use external fmt header-only library instead of bundled" OFF) @@ -144,6 +145,19 @@ option( option(SPDLOG_DISABLE_DEFAULT_LOGGER "Disable default logger creation" OFF) option(SPDLOG_FWRITE_UNLOCKED "Use the unlocked variant of fwrite. Leave this on unless your libc doesn't have it" ON) +set(SPDLOG_WCHAR_TO_UTF8_SUPPORT ${SPDLOG_WCHAR_SUPPORT}) +set(SPDLOG_UTF8_TO_WCHAR_CONSOLE ${SPDLOG_WCHAR_CONSOLE}) + +if(SPDLOG_GENERATE_TWEAKME_H) + if(SPDLOG_FMT_EXTERNAL OR SPDLOG_FMT_EXTERNAL_HO) + set(SPDLOG_TWEAKME_FMT_EXTERNAL_DEFINITION "#define SPDLOG_FMT_EXTERNAL") + else() + set(SPDLOG_TWEAKME_FMT_EXTERNAL_DEFINITION "/* #undef SPDLOG_FMT_EXTERNAL */") + endif() + file(MAKE_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/include/spdlog") + configure_file(cmake/tweakme.h.in "${CMAKE_CURRENT_BINARY_DIR}/include/spdlog/tweakme.h" @ONLY) +endif() + # clang-tidy option(SPDLOG_TIDY "run clang-tidy" OFF) @@ -194,6 +208,10 @@ if(SPDLOG_SYSTEM_INCLUDES) endif() target_compile_definitions(spdlog PUBLIC SPDLOG_COMPILED_LIB) +if(SPDLOG_GENERATE_TWEAKME_H) + target_include_directories( + spdlog ${SPDLOG_INCLUDES_LEVEL} BEFORE PUBLIC "$") +endif() target_include_directories(spdlog ${SPDLOG_INCLUDES_LEVEL} PUBLIC "$" "$") target_link_libraries(spdlog PUBLIC Threads::Threads) @@ -221,6 +239,11 @@ endif() add_library(spdlog_header_only INTERFACE) add_library(spdlog::spdlog_header_only ALIAS spdlog_header_only) +if(SPDLOG_GENERATE_TWEAKME_H) + target_include_directories( + spdlog_header_only ${SPDLOG_INCLUDES_LEVEL} BEFORE INTERFACE + "$") +endif() target_include_directories( spdlog_header_only ${SPDLOG_INCLUDES_LEVEL} INTERFACE "$" "$") @@ -275,8 +298,6 @@ endif() # --------------------------------------------------------------------------------------- # Misc definitions according to tweak options # --------------------------------------------------------------------------------------- -set(SPDLOG_WCHAR_TO_UTF8_SUPPORT ${SPDLOG_WCHAR_SUPPORT}) -set(SPDLOG_UTF8_TO_WCHAR_CONSOLE ${SPDLOG_WCHAR_CONSOLE}) foreach( SPDLOG_OPTION SPDLOG_WCHAR_TO_UTF8_SUPPORT @@ -363,7 +384,14 @@ if(SPDLOG_INSTALL) # --------------------------------------------------------------------------------------- # Include files # --------------------------------------------------------------------------------------- - install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" PATTERN "fmt/bundled" EXCLUDE) + if(SPDLOG_GENERATE_TWEAKME_H) + install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" PATTERN "fmt/bundled" EXCLUDE + PATTERN "tweakme.h" EXCLUDE) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/include/spdlog/tweakme.h" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/spdlog") + else() + install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}" PATTERN "fmt/bundled" EXCLUDE) + endif() install( TARGETS spdlog spdlog_header_only EXPORT spdlog diff --git a/cmake/tweakme.h.in b/cmake/tweakme.h.in new file mode 100644 index 000000000..1ba1b6ce9 --- /dev/null +++ b/cmake/tweakme.h.in @@ -0,0 +1,25 @@ +// Copyright(c) 2015-present, Gabi Melman & spdlog contributors. +// Distributed under the MIT License (http://opensource.org/licenses/MIT) + +#pragma once + +// Generated by CMake. Configure spdlog with SPDLOG_GENERATE_TWEAKME_H=OFF to +// use the editable source-tree tweakme.h instead. + +#define SPDLOG_TWEAKME_H_GENERATED 1 + +#cmakedefine SPDLOG_CLOCK_COARSE +#cmakedefine SPDLOG_NO_THREAD_ID +#cmakedefine SPDLOG_NO_TLS +#cmakedefine SPDLOG_NO_ATOMIC_LEVELS +#cmakedefine SPDLOG_WCHAR_FILENAMES + +@SPDLOG_TWEAKME_FMT_EXTERNAL_DEFINITION@ + +#cmakedefine SPDLOG_USE_STD_FORMAT +#cmakedefine SPDLOG_WCHAR_TO_UTF8_SUPPORT +#cmakedefine SPDLOG_UTF8_TO_WCHAR_CONSOLE +#cmakedefine SPDLOG_PREVENT_CHILD_FD +#cmakedefine SPDLOG_DISABLE_DEFAULT_LOGGER +#cmakedefine SPDLOG_NO_EXCEPTIONS +#cmakedefine SPDLOG_NO_TZ_OFFSET diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 51785a565..a7e92d639 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -94,3 +94,14 @@ endif() if(SPDLOG_BUILD_TESTS_HO OR SPDLOG_BUILD_ALL) spdlog_prepare_test(spdlog-utests-ho spdlog::spdlog_header_only) endif() + +if(SPDLOG_MASTER_PROJECT AND NOT CMAKE_CROSSCOMPILING) + add_test( + NAME spdlog-cmake-tweakme + COMMAND + ${CMAKE_COMMAND} -DSPDLOG_TEST_SOURCE_DIR=${CMAKE_CURRENT_LIST_DIR}/.. + -DSPDLOG_TEST_BINARY_DIR=${CMAKE_CURRENT_BINARY_DIR}/cmake-tweakme + -DSPDLOG_TEST_GENERATOR=${CMAKE_GENERATOR} -DSPDLOG_TEST_GENERATOR_PLATFORM=${CMAKE_GENERATOR_PLATFORM} + -DSPDLOG_TEST_GENERATOR_TOOLSET=${CMAKE_GENERATOR_TOOLSET} -DSPDLOG_TEST_CXX_COMPILER=${CMAKE_CXX_COMPILER} + -DSPDLOG_TEST_CONFIG=$ -P ${CMAKE_CURRENT_LIST_DIR}/cmake/tweakme_test.cmake) +endif() diff --git a/tests/cmake/tweakme/CMakeLists.txt b/tests/cmake/tweakme/CMakeLists.txt new file mode 100644 index 000000000..9bfd16496 --- /dev/null +++ b/tests/cmake/tweakme/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.10) +project(spdlog_tweakme_consumer LANGUAGES CXX) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +if(SPDLOG_TEST_INSTALLED) + find_package(spdlog CONFIG REQUIRED) + + add_executable(package-compiled main.cpp) + target_link_libraries(package-compiled PRIVATE spdlog::spdlog) + + add_executable(package-header-only main.cpp) + target_link_libraries(package-header-only PRIVATE spdlog::spdlog_header_only) + + find_package(Threads REQUIRED) + add_executable(raw-header-only main.cpp) + target_include_directories(raw-header-only PRIVATE "${SPDLOG_TEST_PREFIX}/include") + target_link_libraries(raw-header-only PRIVATE Threads::Threads) +else() + set(SPDLOG_GENERATE_TWEAKME_H ON CACHE BOOL "" FORCE) + set(SPDLOG_NO_THREAD_ID ON CACHE BOOL "" FORCE) + set(SPDLOG_NO_TLS ON CACHE BOOL "" FORCE) + set(SPDLOG_DISABLE_DEFAULT_LOGGER ON CACHE BOOL "" FORCE) + set(SPDLOG_BUILD_SHARED ${SPDLOG_TEST_SHARED} CACHE BOOL "" FORCE) + set(SPDLOG_BUILD_EXAMPLE OFF CACHE BOOL "" FORCE) + set(SPDLOG_BUILD_TESTS OFF CACHE BOOL "" FORCE) + set(SPDLOG_INSTALL ON CACHE BOOL "" FORCE) + add_subdirectory("${SPDLOG_TEST_SOURCE_DIR}" spdlog) + + add_executable(source-compiled main.cpp) + target_link_libraries(source-compiled PRIVATE spdlog::spdlog) + + add_executable(source-header-only main.cpp) + target_link_libraries(source-header-only PRIVATE spdlog::spdlog_header_only) +endif() diff --git a/tests/cmake/tweakme/main.cpp b/tests/cmake/tweakme/main.cpp new file mode 100644 index 000000000..1c51d975d --- /dev/null +++ b/tests/cmake/tweakme/main.cpp @@ -0,0 +1,19 @@ +#include + +#ifndef SPDLOG_TWEAKME_H_GENERATED +#error The generated tweakme.h must be selected before the source header +#endif + +#ifndef SPDLOG_NO_THREAD_ID +#error SPDLOG_NO_THREAD_ID must be provided by the generated tweakme.h +#endif + +#ifndef SPDLOG_NO_TLS +#error SPDLOG_NO_TLS must be provided by the generated tweakme.h +#endif + +#ifndef SPDLOG_DISABLE_DEFAULT_LOGGER +#error SPDLOG_DISABLE_DEFAULT_LOGGER must be provided by the generated tweakme.h +#endif + +int main() { return 0; } diff --git a/tests/cmake/tweakme_test.cmake b/tests/cmake/tweakme_test.cmake new file mode 100644 index 000000000..d602dc7fe --- /dev/null +++ b/tests/cmake/tweakme_test.cmake @@ -0,0 +1,66 @@ +function(run_checked description) + execute_process(COMMAND ${ARGN} RESULT_VARIABLE result OUTPUT_VARIABLE output ERROR_VARIABLE error) + if(NOT result EQUAL 0) + message(FATAL_ERROR "${description} failed (${result}):\n${output}\n${error}") + endif() +endfunction() + +function(configure_checked description source_dir build_dir) + file(MAKE_DIRECTORY "${build_dir}") + execute_process( + COMMAND "${CMAKE_COMMAND}" ${ARGN} "${source_dir}" + WORKING_DIRECTORY "${build_dir}" + RESULT_VARIABLE result + OUTPUT_VARIABLE output + ERROR_VARIABLE error) + if(NOT result EQUAL 0) + message(FATAL_ERROR "${description} failed (${result}):\n${output}\n${error}") + endif() +endfunction() + +function(test_tweakme_configuration library_type shared) + set(build_dir "${SPDLOG_TEST_BINARY_DIR}/${library_type}/build") + set(prefix "${SPDLOG_TEST_BINARY_DIR}/${library_type}/prefix") + set(consumer_dir "${SPDLOG_TEST_BINARY_DIR}/${library_type}/consumer") + file(REMOVE_RECURSE "${SPDLOG_TEST_BINARY_DIR}/${library_type}") + + set(generator_args -G "${SPDLOG_TEST_GENERATOR}") + if(SPDLOG_TEST_GENERATOR_PLATFORM) + list(APPEND generator_args -A "${SPDLOG_TEST_GENERATOR_PLATFORM}") + endif() + if(SPDLOG_TEST_GENERATOR_TOOLSET) + list(APPEND generator_args -T "${SPDLOG_TEST_GENERATOR_TOOLSET}") + endif() + + set(common_args + "-DCMAKE_CXX_COMPILER=${SPDLOG_TEST_CXX_COMPILER}" + "-DCMAKE_BUILD_TYPE=${SPDLOG_TEST_CONFIG}") + + configure_checked( + "Configure ${library_type} source-tree consumer" + "${CMAKE_CURRENT_LIST_DIR}/tweakme" "${build_dir}" ${generator_args} ${common_args} + "-DSPDLOG_TEST_SOURCE_DIR=${SPDLOG_TEST_SOURCE_DIR}" "-DSPDLOG_TEST_SHARED=${shared}" + "-DCMAKE_INSTALL_PREFIX=${prefix}") + run_checked("Build ${library_type} source-tree consumer" "${CMAKE_COMMAND}" --build "${build_dir}" --config + "${SPDLOG_TEST_CONFIG}") + run_checked("Install ${library_type} spdlog" "${CMAKE_COMMAND}" --build "${build_dir}" --target install --config + "${SPDLOG_TEST_CONFIG}") + + set(installed_tweakme "${prefix}/include/spdlog/tweakme.h") + file(READ "${installed_tweakme}" tweakme_contents) + foreach(expected_macro SPDLOG_NO_THREAD_ID SPDLOG_NO_TLS SPDLOG_DISABLE_DEFAULT_LOGGER) + if(NOT tweakme_contents MATCHES "#define ${expected_macro}([\r\n]|$)") + message(FATAL_ERROR "${installed_tweakme} does not define ${expected_macro}") + endif() + endforeach() + + configure_checked( + "Configure ${library_type} installed consumers" + "${CMAKE_CURRENT_LIST_DIR}/tweakme" "${consumer_dir}" ${generator_args} ${common_args} + -DSPDLOG_TEST_INSTALLED=ON "-DSPDLOG_TEST_PREFIX=${prefix}" "-DCMAKE_PREFIX_PATH=${prefix}") + run_checked("Build ${library_type} installed consumers" "${CMAKE_COMMAND}" --build "${consumer_dir}" --config + "${SPDLOG_TEST_CONFIG}") +endfunction() + +test_tweakme_configuration(static OFF) +test_tweakme_configuration(shared ON)