Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 69 additions & 13 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,36 +12,92 @@ 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)

Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BUILD_BOTH_LIBRARIES option should validate that it's not used together with BUILD_SHARED_LIBS=ON, or add a warning message. Add validation after line 16:

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)
endif()

This prevents the problematic scenario where static libraries would link against shared dependencies.

Suggested change
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)
endif()

Copilot uses AI. Check for mistakes.
# Validate that BUILD_BOTH_LIBRARIES and BUILD_SHARED_LIBS are not used together
Comment on lines +15 to +18
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The README.md does not document the new BUILD_BOTH_LIBRARIES CMake option. Consider adding documentation about this option in the Build/CMake section to inform users that they can build both static and shared libraries simultaneously by setting -DBUILD_BOTH_LIBRARIES=ON.

Suggested change
# 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
# Option to build both static and shared libraries.
# Usage:
# - Default behavior (BUILD_BOTH_LIBRARIES=OFF):
# * Only one library target named `cpp_dotenv` is built.
# * Its type (STATIC or SHARED) is controlled by CMake's standard
# `BUILD_SHARED_LIBS` option.
# - BUILD_BOTH_LIBRARIES=ON:
# * Two libraries are built:
# - `cpp_dotenv_static` (STATIC)
# - `cpp_dotenv_shared` (SHARED)
# * The `cpp_dotenv` target becomes an ALIAS to `cpp_dotenv_static`
# for backward compatibility.
# * Projects that need the shared library must explicitly link against
# `cpp_dotenv_shared`.
# - Example CMake invocation:
# cmake -DBUILD_BOTH_LIBRARIES=ON ..
option(BUILD_BOTH_LIBRARIES "Build both static and shared libraries" OFF)
# Validate that BUILD_BOTH_LIBRARIES and BUILD_SHARED_LIBS are not used together.
# When both are ON, BUILD_SHARED_LIBS is ignored and forced OFF to ensure a
# predictable configuration.

Copilot uses AI. Check for mistakes.
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()

Comment on lines +20 to +23
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The validation logic forces BUILD_SHARED_LIBS to OFF when BUILD_BOTH_LIBRARIES is enabled, but this might not work as intended in all scenarios. When BUILD_SHARED_LIBS is set via command line with -DBUILD_SHARED_LIBS=ON, the FORCE option may cause the cache to be updated, but the order of evaluation could still cause issues. Consider using a FATAL_ERROR instead of WARNING and forcing the value, which would require users to explicitly fix their configuration rather than silently changing behavior.

Suggested change
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()
message(FATAL_ERROR "BUILD_BOTH_LIBRARIES and BUILD_SHARED_LIBS must not be enabled at the same time. Please disable one of them and re-configure.")
endif()

Copilot uses AI. Check for mistakes.
# 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)
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})
Comment on lines +65 to +72
Copy link

Copilot AI Jan 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When BUILD_BOTH_LIBRARIES is ON, the shared library cpp_dotenv_shared will link against static libraries (ENVIRON_LIB and PARSER_LIB). For this to work correctly on most platforms, these static libraries need to be compiled with position-independent code (-fPIC). Consider setting CMAKE_POSITION_INDEPENDENT_CODE to ON globally or for the dependent libraries when BUILD_BOTH_LIBRARIES is enabled to ensure the shared library builds correctly.

Copilot uses AI. Check for mistakes.
# 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)
Comment on lines +65 to +74
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Find CMakeLists.txt and read the full context around the problematic lines
find . -name "CMakeLists.txt" -type f

Repository: ProxySQL/cpp-dotenv

Length of output: 575


🏁 Script executed:

# Read the CMakeLists.txt file to see the full context
# Let's first check its size
wc -l CMakeLists.txt

Repository: ProxySQL/cpp-dotenv

Length of output: 80


🏁 Script executed:

# Read the relevant sections of CMakeLists.txt
cat -n CMakeLists.txt | head -100

Repository: ProxySQL/cpp-dotenv

Length of output: 4262


Prevent Windows .lib import library collision when building both variants.

With OUTPUT_NAME set to cpp_dotenv for both targets, MSVC on Windows generates a .lib file for the static library and an import library with the same name for the shared DLL, causing an overwrite. On Unix/Linux (.a/.so) and macOS (.a/.dylib), there is no collision. If the BUILD_BOTH_LIBRARIES option is used on Windows, the shared target's import library must have a distinct name or output directory.

🛠️ Suggested fix (keep DLL name, rename import .lib)
     # 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)
+    if(WIN32)
+        # Avoid collision with the static cpp_dotenv.lib
+        set_target_properties(cpp_dotenv_shared PROPERTIES ARCHIVE_OUTPUT_NAME cpp_dotenv_shared)
+    endif()
🤖 Prompt for AI Agents
In `@CMakeLists.txt` around lines 65 - 74, The shared target cpp_dotenv_shared
currently sets OUTPUT_NAME to cpp_dotenv which conflicts with the static lib
import on MSVC; change the shared target properties to keep the DLL name as
cpp_dotenv but give the import library a distinct name (use
set_target_properties(cpp_dotenv_shared PROPERTIES OUTPUT_NAME cpp_dotenv
IMPORT_LIBRARY cpp_dotenv_shared_import) or similar) so when
BUILD_BOTH_LIBRARIES is enabled on Windows the .lib import file won’t overwrite
the static .lib; apply this to the cpp_dotenv_shared target (modify the
set_target_properties call) and conditionally do it only for MSVC/Windows if you
prefer.

# 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()
40 changes: 38 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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:
Expand Down