diff --git a/CMakeLists.txt b/CMakeLists.txt index 9fb67a4..49e0468 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -12,6 +12,21 @@ else() endif() message(STATUS "Building CPP-DOTENV in ${CMAKE_BUILD_TYPE} mode") +# Option to build both static and shared libraries +option(BUILD_BOTH_LIBRARIES "Build both static and shared libraries" OFF) + +# Validate that BUILD_BOTH_LIBRARIES and BUILD_SHARED_LIBS are not used together +if(BUILD_BOTH_LIBRARIES AND BUILD_SHARED_LIBS) + message(WARNING "BUILD_BOTH_LIBRARIES and BUILD_SHARED_LIBS should not be used together. BUILD_SHARED_LIBS will be ignored.") + set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libraries" FORCE) +endif() + +# When building shared libraries that link against static libraries, +# we need position-independent code for the static libraries +if(BUILD_SHARED_LIBS OR BUILD_BOTH_LIBRARIES) + set(CMAKE_POSITION_INDEPENDENT_CODE ON) +endif() + #------------------- SUBDIRECTORY ADDITION ------------------------------------ add_subdirectory(common) @@ -19,29 +34,70 @@ add_subdirectory(src) #----------------------- LIBRARY CONFIGURATION -------------------------------- -set(CPP_DOTENV cpp_dotenv CACHE INTERNAL "") set(CPP_DOTENV_SRC src/dotenv.cpp include/dotenv.h ) -add_library(${CPP_DOTENV} ${CPP_DOTENV_SRC}) +# Common include directories +set(CPP_DOTENV_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/include) -target_link_libraries(${CPP_DOTENV} - ${ENVIRON_LIB} - ${PARSER_LIB} -) +# Common compile options +if ("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") + set(CPP_DOTENV_COMPILE_OPTIONS -g -Wall -O0) +else() + set(CPP_DOTENV_COMPILE_OPTIONS -O3) +endif() -target_include_directories(${CPP_DOTENV} PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/include -) +# Build both static and shared libraries if requested +if(BUILD_BOTH_LIBRARIES) + # Static library + add_library(cpp_dotenv_static STATIC ${CPP_DOTENV_SRC}) + target_link_libraries(cpp_dotenv_static + ${ENVIRON_LIB} + ${PARSER_LIB} + ) + target_include_directories(cpp_dotenv_static PUBLIC ${CPP_DOTENV_INCLUDE_DIRS}) + target_compile_options(cpp_dotenv_static PRIVATE ${CPP_DOTENV_COMPILE_OPTIONS}) + # Set output name to libcpp_dotenv.a (instead of libcpp_dotenv_static.a) + set_target_properties(cpp_dotenv_static PROPERTIES OUTPUT_NAME cpp_dotenv) -if ("${CMAKE_BUILD_TYPE}" STREQUAL "DEBUG") - target_compile_options(${CPP_DOTENV} PRIVATE - -g -Wall -O0 + # Shared library + add_library(cpp_dotenv_shared SHARED ${CPP_DOTENV_SRC}) + target_link_libraries(cpp_dotenv_shared + ${ENVIRON_LIB} + ${PARSER_LIB} ) + target_include_directories(cpp_dotenv_shared PUBLIC ${CPP_DOTENV_INCLUDE_DIRS}) + target_compile_options(cpp_dotenv_shared PRIVATE ${CPP_DOTENV_COMPILE_OPTIONS}) + # Set output name to libcpp_dotenv.so/.dylib (instead of libcpp_dotenv_shared.so) + set_target_properties(cpp_dotenv_shared PROPERTIES OUTPUT_NAME cpp_dotenv) + # On Windows (MSVC), the import library would conflict with the static library. + # Add a suffix to the import library name to avoid this conflict. + if(MSVC) + set_target_properties(cpp_dotenv_shared PROPERTIES IMPORT_SUFFIX "_shared.lib") + endif() + + # Alias for backward compatibility: + # When BUILD_BOTH_LIBRARIES is ON, the cpp_dotenv target is an alias to + # cpp_dotenv_static. Projects that need the shared library must explicitly + # link against cpp_dotenv_shared instead of cpp_dotenv. + add_library(cpp_dotenv ALIAS cpp_dotenv_static) else() + # Single library (type determined by BUILD_SHARED_LIBS) + set(CPP_DOTENV cpp_dotenv CACHE INTERNAL "") + add_library(${CPP_DOTENV} ${CPP_DOTENV_SRC}) + + target_link_libraries(${CPP_DOTENV} + ${ENVIRON_LIB} + ${PARSER_LIB} + ) + + target_include_directories(${CPP_DOTENV} PUBLIC + ${CPP_DOTENV_INCLUDE_DIRS} + ) + target_compile_options(${CPP_DOTENV} PRIVATE - -O3 + ${CPP_DOTENV_COMPILE_OPTIONS} ) endif() diff --git a/README.md b/README.md index aad33c5..24a0a63 100644 --- a/README.md +++ b/README.md @@ -39,11 +39,11 @@ C++ implementation of NodeJS [dotenv](https://github.com/motdotla/dotenv) projec Supported build methods are: -- [CMake](#cmake) (>=3.10) +- [CMake](#cmake) (>=3.16) ### CMake -**cpp-dotenv** comes with support for `CMake` right out of the box. In order to use it, simply include this repository's directory and link the `cpp_dotenv` target to your own targets where needed: +**cpp-dotenv** comes with support for `CMake` right out of the box (>=3.16). In order to use it, simply include this repository's directory and link the `cpp_dotenv` target to your own targets where needed: ```cmake add_subdirectory(cpp-dotenv) @@ -55,6 +55,42 @@ target_link_libraries(YOUR_TARGET cpp_dotenv) After this, you might use the library as described in [usage](#usage); no extra scoping, no need to worry about the project's directory structure. +#### Build Options + +By default, only one library target named `cpp_dotenv` is built. The type of library (static or shared) is controlled by CMake's standard `BUILD_SHARED_LIBS` option: + +```bash +# Build static library (default) +cmake -DBUILD_SHARED_LIBS=OFF .. + +# Build shared library +cmake -DBUILD_SHARED_LIBS=ON .. +``` + +#### Building Both Static and Shared Libraries + +To build both static and shared libraries in a single build directory, use the `BUILD_BOTH_LIBRARIES` option: + +```bash +cmake -DBUILD_BOTH_LIBRARIES=ON .. +``` + +This creates two separate library targets: +- `cpp_dotenv_static` - outputs as `libcpp_dotenv.a` +- `cpp_dotenv_shared` - outputs as `libcpp_dotenv.so` (or `.dylib` on macOS) + +For backward compatibility, the `cpp_dotenv` target remains available as an alias to `cpp_dotenv_static`. If you need to link against the shared library, explicitly specify `cpp_dotenv_shared`: + +```cmake +# Link against static library (default) +target_link_libraries(YOUR_TARGET cpp_dotenv) + +# Link against shared library +target_link_libraries(YOUR_TARGET cpp_dotenv_shared) +``` + +**Note:** When `BUILD_BOTH_LIBRARIES` is enabled, `BUILD_SHARED_LIBS` is ignored. Do not use both options simultaneously. + ## Usage To be able to use the dotenv classes, simply include the main header file: