diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index efdc5ecfb..440c6cbfb 100755 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -31,6 +31,9 @@ if (POLICY CMP0079) endif () set(TsFile_CPP_VERSION 2.3.2.dev) +option(TSFILE_BUILD_SHARED "Build libtsfile as a shared library" ON) +message("cmake using: TSFILE_BUILD_SHARED=${TSFILE_BUILD_SHARED}") + if (MSVC) # MSVC does not provide a /std:c++11 flag; C++11 is its implicit baseline. # The lowest explicitly settable standard is /std:c++14. Without this flag, @@ -39,9 +42,11 @@ if (MSVC) set(CMAKE_CXX_FLAGS "$ENV{CXXFLAGS} /W3 /utf-8 /EHsc /bigobj /Zc:__cplusplus /std:c++14") add_definitions(-DNOMINMAX -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS -D_WINSOCK_DEPRECATED_NO_WARNINGS) - # Export all symbols of the tsfile shared library automatically so that - # consumers do not need __declspec(dllexport) annotations. - set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + if (TSFILE_BUILD_SHARED) + # Export all symbols of the tsfile shared library automatically so that + # consumers do not need __declspec(dllexport) annotations. + set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) + endif () else () set(CMAKE_CXX_FLAGS "$ENV{CXXFLAGS} -Wall") endif () diff --git a/cpp/README.md b/cpp/README.md index 639aa38f7..918eff68f 100644 --- a/cpp/README.md +++ b/cpp/README.md @@ -132,7 +132,29 @@ mvn clean verify -P with-cpp -Dcpp.toolchain=mingw mvn clean verify -P with-cpp -Dcpp.toolchain=msvc ``` -Then you can find the shared library at `./cpp/target/build/lib`. +By default, the shared library is written to `./cpp/target/build/lib`. + +To build `libtsfile` as a static library instead, disable +`TSFILE_BUILD_SHARED` through Maven: + +```bash +mvn clean verify -P with-cpp -Dtsfile.build.shared=OFF +``` + +The static library is written to the same directory (`libtsfile.a` on +Linux/macOS and `tsfile.lib` on Windows). When consuming the installed archive +directly on MSVC rather than linking the CMake `tsfile` target, define +`TSFILE_STATIC` for the consumer so public headers do not use DLL import +decorations. + +For a direct CMake build, use: + +```bash +cmake -S cpp -B cpp/build/static \ + -DTSFILE_BUILD_SHARED=OFF \ + -DBUILD_TEST=OFF +cmake --build cpp/build/static --target tsfile +``` Before you submit your code to GitHub, please ensure that the compilation is correct. diff --git a/cpp/build.sh b/cpp/build.sh index f51c4eded..3cc100c13 100644 --- a/cpp/build.sh +++ b/cpp/build.sh @@ -20,6 +20,7 @@ # build_type=MinSizeRel build_type=Release build_test=0 +build_shared=ON build_bench=0 do_install=0 use_cpp11=1 @@ -52,6 +53,9 @@ Options: -t=, -t Build type: Debug, Release, RelWithDebInfo, MinSizeRel. -a= Enable or disable AddressSanitizer. -c= Enable or disable code coverage. + --build-shared= + Build libtsfile as a shared library (default: ON). + --build-static Build libtsfile as a static library. --enable-antlr4= --disable-antlr4 --enable-snappy= @@ -70,6 +74,7 @@ function print_config() { echo "build_type=$build_type" echo "build_test=$build_test" + echo "build_shared=$build_shared" echo "do_install=$do_install" echo "use_cpp11=$use_cpp11" echo "enable_cov=$enable_cov" @@ -113,6 +118,10 @@ parse_options() -c) shift enable_cov=$(get_key_value "$1");; + --build-shared=*) + build_shared=$(get_key_value "$1");; + --build-static) + build_shared=OFF;; --enable-antlr4=*) enable_antlr4=$(get_key_value "$1");; --enable-snappy=*) @@ -190,6 +199,7 @@ cmake ../../ \ -DZLIB=$zlib_project_dir/install \ -DLZ4LIB=$lz4lib_project_dir \ -DBUILD_TEST=$build_test \ + -DTSFILE_BUILD_SHARED=$build_shared \ -DCMAKE_BUILD_TYPE=$build_type \ -DUSE_CPP11=$use_cpp11 \ -DENABLE_COV=$enable_cov \ diff --git a/cpp/pom.xml b/cpp/pom.xml index c4ea285d4..9b47ce0a7 100644 --- a/cpp/pom.xml +++ b/cpp/pom.xml @@ -35,6 +35,7 @@ Release OFF ON + ON ON ON ON @@ -82,6 +83,7 @@ + diff --git a/cpp/src/CMakeLists.txt b/cpp/src/CMakeLists.txt index 895c1ddba..41d2cde12 100644 --- a/cpp/src/CMakeLists.txt +++ b/cpp/src/CMakeLists.txt @@ -101,10 +101,14 @@ endif() include_directories(${PROJECT_INCLUDE_DIR}) -# Mark every translation unit that is compiled into the tsfile library so that -# TSFILE_API (see utils/util_define.h) resolves to an export-side (empty) -# decoration here, and to __declspec(dllimport) for external consumers. -add_definitions(-DTSFILE_BUILDING) +# Configure TSFILE_API (see utils/util_define.h) for every translation unit +# compiled into the tsfile library. Shared builds export data symbols, while +# static builds do not use DLL import/export decorations. +if (TSFILE_BUILD_SHARED) + add_definitions(-DTSFILE_BUILDING) +else() + add_definitions(-DTSFILE_STATIC) +endif() if (ENABLE_ANTLR4) add_subdirectory(parser) @@ -150,7 +154,14 @@ target_link_libraries(common_obj ${COMPRESSION_LIBS}) target_link_libraries(read_obj ${COMPRESSION_LIBS}) target_link_libraries(write_obj ${COMPRESSION_LIBS}) -add_library(tsfile SHARED) +if (TSFILE_BUILD_SHARED) + add_library(tsfile SHARED) +else() + add_library(tsfile STATIC) + # Consumers of the CMake target must see TSFILE_API without DLL import + # decoration when linking the static library on MSVC. + target_compile_definitions(tsfile INTERFACE TSFILE_STATIC) +endif() if (${COV_ENABLED}) message("Enable code cov...") @@ -177,14 +188,16 @@ endif() add_dependencies(tsfile utils_obj encoding_obj) -set(LIBTSFILE_PROJECT_VERSION ${TsFile_CPP_VERSION}) -set(LIBTSFILE_SO_VERSION ${TsFile_CPP_VERSION}) -set_target_properties(tsfile PROPERTIES VERSION ${LIBTSFILE_PROJECT_VERSION}) -set_target_properties(tsfile PROPERTIES SOVERSION ${LIBTSFILE_SO_VERSION}) +if (TSFILE_BUILD_SHARED) + set(LIBTSFILE_PROJECT_VERSION ${TsFile_CPP_VERSION}) + set(LIBTSFILE_SO_VERSION ${TsFile_CPP_VERSION}) + set_target_properties(tsfile PROPERTIES VERSION ${LIBTSFILE_PROJECT_VERSION}) + set_target_properties(tsfile PROPERTIES SOVERSION ${LIBTSFILE_SO_VERSION}) +endif() -# On Windows a SHARED library produces a .dll (RUNTIME) plus an import .lib -# (ARCHIVE); on Unix it produces a .so (LIBRARY). Cover all three so the -# install step works for every platform. +# A shared library is a RUNTIME plus an import ARCHIVE on Windows and a LIBRARY +# on Unix. A static library is an ARCHIVE on every platform. Cover all three so +# the install step works for either library type. install(TARGETS tsfile RUNTIME DESTINATION ${LIBRARY_OUTPUT_PATH} LIBRARY DESTINATION ${LIBRARY_OUTPUT_PATH} diff --git a/cpp/src/utils/util_define.h b/cpp/src/utils/util_define.h index ee96616f1..564581a11 100644 --- a/cpp/src/utils/util_define.h +++ b/cpp/src/utils/util_define.h @@ -64,17 +64,18 @@ typedef int mode_t; #endif #endif // _WIN32 -/* ======== shared-library symbol visibility ======== +/* ======== library symbol visibility ======== * * Functions are exported from tsfile.dll automatically via * CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS, but global DATA symbols (plain variables, * static class members) are not reliably auto-exported, and a consumer must * see __declspec(dllimport) to reference them across the DLL boundary. Mark * such symbols with TSFILE_API: it expands to dllexport while building the - * library (TSFILE_BUILDING is defined for its own translation units), - * dllimport for external consumers, and nothing on non-MSVC toolchains. + * shared library (TSFILE_BUILDING is defined for its own translation units), + * dllimport for shared-library consumers, and nothing for static builds or + * non-MSVC toolchains. */ -#if defined(_MSC_VER) +#if defined(_MSC_VER) && !defined(TSFILE_STATIC) #if defined(TSFILE_BUILDING) #define TSFILE_API __declspec(dllexport) #else diff --git a/cpp/test/CMakeLists.txt b/cpp/test/CMakeLists.txt index 066e5accb..7fc9041b1 100644 --- a/cpp/test/CMakeLists.txt +++ b/cpp/test/CMakeLists.txt @@ -258,7 +258,7 @@ set_target_properties(TsFile_Test PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${LIB_TSFI # On Windows, copy tsfile DLL next to the test exe so it can load at runtime # (and when gtest_discover_tests runs the exe). Use TARGET_FILE so the path # is correct for the current build config (e.g. Release). -if (WIN32) +if (WIN32 AND TSFILE_BUILD_SHARED) add_custom_command(TARGET TsFile_Test POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $