diff --git a/CMakeLists.txt b/CMakeLists.txt index f1dcfba..8bc3c52 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,22 +22,13 @@ elseif(${CMAKE_CXX_COMPILER_ID} STREQUAL Clang) endif() option(SIMSTR_BUILD_TESTS "Построить тесты" ON) -option(SIMSTR_BENCHMARKS "Построить замеры производительности" ON) -option(SIMSTR_SHARED "Функции simstr должны экспортироваться или импортироваться" OFF) +option(SIMSTR_BENCHMARKS "Построить замеры производительности" Off) -if(EMSCRIPTEN) - option(SIMSTR_EMSCRIPTEN_MT "Использовать многопоточность в Emscripten" OFF) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-warn-absolute-paths -Wno-unknown-warning-option -msimd128 -msse4.2 -msse3") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-warn-absolute-paths -Wno-unknown-warning-option -msimd128 -msse4.2 -msse3") - - if(SIMSTR_EMSCRIPTEN_MT) - message("Build MT emscripten") - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pthread") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread -sPTHREAD_POOL_SIZE=navigator.hardwareConcurrency-1") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -sENVIRONMENT=web,worker") - endif() -endif(EMSCRIPTEN) +# При OFF - строится обычная статическая библиотека. +# При On - simstr собирается как статическая библиотека, которую потом встроят в shared библиотеку, +# и она будет свои функции объявлять как экспортируемые. Потребители же будут собираться с указанием, +# что функции - импортируемые +option(SIMSTR_IN_SHARED "Функции simstr будут экспортироваться или импортироваться" Off) add_library(simstr_simstr src/sstring.cpp @@ -53,6 +44,16 @@ target_include_directories( target_compile_features(simstr_simstr PUBLIC cxx_std_20) +if(EMSCRIPTEN) + option(SIMSTR_EMSCRIPTEN_MT "Использовать многопоточность в Emscripten" OFF) + target_compile_options(simstr_simstr PUBLIC -Wno-warn-absolute-paths -Wno-unknown-warning-option -msimd128 -msse4.2 -msse3) + + if(SIMSTR_EMSCRIPTEN_MT) + message("Build MT emscripten") + target_compile_options(simstr_simstr PUBLIC -pthread) + endif() +endif(EMSCRIPTEN) + # Для MSVC подключаем natvis файл для красивой отладки if(${CMAKE_CXX_COMPILER_ID} STREQUAL MSVC) target_link_options(simstr_simstr PUBLIC "/natvis:${CMAKE_CURRENT_SOURCE_DIR}/for_debug/simstr.natvis") @@ -68,7 +69,7 @@ set_target_properties( OUTPUT_NAME simstr ) -function(Simdutf) +function(add_simdutf) set(SIMDUTF_TOOLS OFF) set(SIMDUTF_TESTS OFF) set(SIMDUTF_BENCHMARKS OFF) @@ -82,14 +83,22 @@ function(Simdutf) FetchContent_MakeAvailable(simdutf) endfunction() -Simdutf() +add_simdutf() target_link_libraries(simstr_simstr PUBLIC simdutf::simdutf) -if(SIMSTR_SHARED) - add_compile_definitions(SIMSTR_SHARED) +if(SIMSTR_IN_SHARED) + # Всем объявляем, что мы будем в shared библиотеке + add_compile_definitions(SIMSTR_IN_SHARED) + # Себе объявим, что мы должны экспортировать функции target_compile_definitions(simstr_simstr PRIVATE SIMSTR_EXPORT) -endif(SIMSTR_SHARED) + # Пример построения shared библиотеки, которая включит в себя simstr. + # Как при этом создать экзешник, пользующийся этой dll - пример в tests/CMakeLists.txt + # Нельзя объявить библиотеку без исходников, добавим просто .h файл + add_library(simstr_dll SHARED include/simstr/sstring.h) + # simstr должна войти в simstr_dll целиком + target_link_libraries(simstr_dll PRIVATE "$") +endif(SIMSTR_IN_SHARED) if(SIMSTR_BUILD_TESTS) enable_testing() @@ -101,7 +110,6 @@ if(SIMSTR_BUILD_TESTS) URL https://github.com/google/googletest/archive/refs/tags/release-1.12.1.zip FIND_PACKAGE_ARGS NAMES GTest ) - # For Windows: Prevent overriding the parent project's compiler/linker settings set(gtest_force_shared_crt FALSE CACHE BOOL "" FORCE) FetchContent_MakeAvailable(googletest) @@ -110,14 +118,12 @@ endif() function(GBencmark) # Load and build Google benchmarks - include(FetchContent) FetchContent_Declare( googlebench # Specify the commit you depend on and update it regularly. - URL https://github.com/google/benchmark/archive/refs/tags/v1.7.0.zip + URL https://github.com/google/benchmark/archive/refs/tags/v1.9.4.zip FIND_PACKAGE_ARGS NAMES benchmark ) - set(CMAKE_CXX_STANDARD 20) set(BENCHMARK_ENABLE_TESTING OFF) set(BENCHMARK_ENABLE_LTO OFF) set(BENCHMARK_ENABLE_INSTALL OFF) @@ -126,6 +132,15 @@ function(GBencmark) set(BENCHMARK_ENABLE_GTEST_TESTS OFF) add_compile_definitions(BENCHMARK_STATIC_DEFINE) FetchContent_MakeAvailable(googlebench) + target_compile_features(benchmark PUBLIC cxx_std_20) + + if(EMSCRIPTEN) + # Свежий Clang в Emscripten ругается на __COUNTER__ + target_compile_options(benchmark PUBLIC -Wno-c2y-extensions) + if(SIMSTR_EMSCRIPTEN_MT) + target_compile_options(benchmark PUBLIC -pthread) + endif() + endif() endfunction() if(SIMSTR_BENCHMARKS) # AND CMAKE_BUILD_TYPE STREQUAL Release) diff --git a/bench/CMakeLists.txt b/bench/CMakeLists.txt index d42b96a..fb0bd70 100644 --- a/bench/CMakeLists.txt +++ b/bench/CMakeLists.txt @@ -4,7 +4,7 @@ cmake_minimum_required (VERSION 3.15) add_executable(benchStr bench_str.cpp bench.h) -target_link_libraries(benchStr simstr::simstr benchmark::benchmark benchmark::benchmark_main) +target_link_libraries(benchStr simstr::simstr benchmark::benchmark) add_executable(process_result process_result.cpp) target_link_libraries(process_result simstr_simstr) @@ -12,5 +12,7 @@ target_link_libraries(process_result simstr_simstr) if (EMSCRIPTEN) #target_link_options(benchStr PRIVATE -sSTACK_SIZE=1048576 -sINITIAL_MEMORY=128MB -sALLOW_MEMORY_GROWTH=0) set_target_properties (benchStr PROPERTIES SUFFIX .html) - target_link_options(benchStr PUBLIC --pre-js ${CMAKE_CURRENT_SOURCE_DIR}/bench.js) + if(SIMSTR_EMSCRIPTEN_MT) + target_link_options(benchStr PUBLIC -pthread -sPTHREAD_POOL_SIZE=navigator.hardwareConcurrency-1 -sENVIRONMENT=web,worker) + endif() endif(EMSCRIPTEN) diff --git a/bench/bench.js b/bench/bench.js deleted file mode 100644 index f0a607a..0000000 --- a/bench/bench.js +++ /dev/null @@ -1 +0,0 @@ -Module.arguments=['--benchmark_repetitions=10', '--benchmark_report_aggregates_only=true']; diff --git a/bench/bench_str.cpp b/bench/bench_str.cpp index 005f5c1..3a85d80 100644 --- a/bench/bench_str.cpp +++ b/bench/bench_str.cpp @@ -145,7 +145,6 @@ void ToIntStr10(benchmark::State& state, const std::string& s, int c) { } #endif benchmark::DoNotOptimize(res); - benchmark::DoNotOptimize(s); } } @@ -159,7 +158,6 @@ void ToIntStr16(benchmark::State& state, const std::string& s, int c) { } #endif benchmark::DoNotOptimize(res); - benchmark::DoNotOptimize(s); } } @@ -173,7 +171,6 @@ void ToIntStr0(benchmark::State& state, const std::string& s, int c) { } #endif benchmark::DoNotOptimize(res); - benchmark::DoNotOptimize(s); } } @@ -191,7 +188,6 @@ void ToIntFromChars10(benchmark::State& state, const std::string_view& s, int c) } #endif benchmark::DoNotOptimize(res); - benchmark::DoNotOptimize(s); } #endif } @@ -210,7 +206,6 @@ void ToIntFromChars16(benchmark::State& state, const std::string_view& s, int c) } #endif benchmark::DoNotOptimize(res); - benchmark::DoNotOptimize(s); } #endif } @@ -890,8 +885,6 @@ void ReplaceSymbolsStdString(benchmark::State& state) { #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); - benchmark::DoNotOptimize(repl_from); - benchmark::DoNotOptimize(repl_to); } } @@ -1112,8 +1105,6 @@ void ShortReplaceSymbolsStdString(benchmark::State& state) { #endif benchmark::DoNotOptimize(result); benchmark::DoNotOptimize(source); - benchmark::DoNotOptimize(repl_from); - benchmark::DoNotOptimize(repl_to); } } @@ -1904,3 +1895,18 @@ BENCHMARK(BuildFuncNameStdStr1) ->Name("Build func full name std::string BENCHMARK(BuildFuncNameStream) ->Name("Build func full name std::stream;"); BENCHMARK(BuildFuncNameSimStr) ->Name("Build func full name stringa;"); BENCHMARK(BuildFuncNameSimStr1) ->Name("Build func full name stringa 1;"); + +int main(int argc, char** argv) { + char arg1[] = "--benchmark_repetitions=10", arg2[] = "--benchmark_report_aggregates_only=true"; + char* my_params[] = {argv[0], arg1, arg2}; + if (argc < 2) { + argc = 3; + argv = my_params; + } + ::benchmark::Initialize(&argc, argv); + if (::benchmark::ReportUnrecognizedArguments(argc, argv)) + return 1; + ::benchmark::RunSpecifiedBenchmarks(); + ::benchmark::Shutdown(); + return 0; +} diff --git a/include/simstr/sstring.h b/include/simstr/sstring.h index 023ef67..abb488b 100644 --- a/include/simstr/sstring.h +++ b/include/simstr/sstring.h @@ -15,7 +15,7 @@ #define __has_declspec_attribute(x) 0 #endif -#ifdef SIMSTR_SHARED +#ifdef SIMSTR_IN_SHARED #if defined(_MSC_VER) || (defined(__clang__) && __has_declspec_attribute(dllexport)) #ifdef SIMSTR_EXPORT #define SIMSTR_API __declspec(dllexport) @@ -41,10 +41,10 @@ const bool isx64 = sizeof(void*) == 8; // NOLINT #ifdef _MSC_VER #define _no_unique_address msvc::no_unique_address -#define empty_bases __declspec(empty_bases) +#define decl_empty_bases __declspec(empty_bases) #else #define _no_unique_address no_unique_address -#define empty_bases +#define decl_empty_bases #endif #if defined __has_builtin @@ -3752,7 +3752,7 @@ class sstring; * выделяется +n байтов, чтобы потом не копировать данные. */ template -class empty_bases lstring : +class decl_empty_bases lstring : public str_algs, lstring, true>, public str_mutable>, public str_storable, Allocator>, @@ -4220,7 +4220,7 @@ constexpr const size_t local_count = _local_count; */ template -class empty_bases sstring : +class decl_empty_bases sstring : public str_algs, sstring, false>, public str_storable, Allocator>, public from_utf_convertable> { @@ -5987,7 +5987,7 @@ using stringa = sstring; using stringw = sstring; using stringu = sstring; using stringuu = sstring; -static_assert(sizeof(stringa) == 24, "Bad size of sstring"); +static_assert(sizeof(stringa) == (sizeof(void*) == 8 ? 24 : 16), "Bad size of sstring"); /*! * @brief Тип хеш-словаря для char строк, регистрозависимый поиск diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index daf74d8..2e7b302 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -3,9 +3,27 @@ # add_executable(testStr test_str.cpp) -target_link_libraries(testStr simstr::simstr GTest::gtest_main) + +if (NOT SIMSTR_IN_SHARED) + target_link_libraries(testStr simstr::simstr GTest::gtest_main) +else() + # Пример создания экзешника, если simstr экспортируются из dll. + # Так как мы подключаем только simstr_dll, и входящие в неё либы не видны + # нужно вручную задать каталоги include и стандарт C++20 + target_link_libraries(testStr simstr_dll GTest::gtest_main) + get_target_property(SIMSTR_INCLUDES simstr::simstr INCLUDE_DIRECTORIES) + target_include_directories(testStr PRIVATE ${SIMSTR_INCLUDES}) + target_compile_features(testStr PUBLIC cxx_std_20) +endif() + add_test(NAME testStr COMMAND testStr) if (EMSCRIPTEN) set_target_properties (testStr PROPERTIES SUFFIX .html) + target_compile_options(testStr PUBLIC -Wno-warn-absolute-paths -Wno-unknown-warning-option -msimd128 -msse4.2 -msse3) + if(SIMSTR_EMSCRIPTEN_MT) + target_compile_options(testStr PUBLIC -pthread) + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pthread -sPTHREAD_POOL_SIZE=navigator.hardwareConcurrency-1") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -sENVIRONMENT=web,worker") + endif() endif(EMSCRIPTEN)