Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
03e897b
test for using CLI11 in a module
phlptp Nov 14, 2025
9f5e375
try to update some code to support inclusion in C++ modules
phlptp Nov 14, 2025
818757c
style: pre-commit.ci fixes
pre-commit-ci[bot] Nov 14, 2025
61d673e
update cmake standard used for some tests
phlptp Nov 14, 2025
c5a0408
more tweaks
phlptp Nov 15, 2025
42f2833
try slightly different definition for string constants
phlptp Nov 15, 2025
fa2347d
style: pre-commit.ci fixes
pre-commit-ci[bot] Nov 15, 2025
4f89361
update some docs and copyright notices on code
phlptp Nov 15, 2025
2006cf1
remove duplicate line
phlptp Nov 15, 2025
cb6350a
style: pre-commit.ci fixes
pre-commit-ci[bot] Nov 15, 2025
759ba3b
update the testing command for the module test
phlptp Nov 15, 2025
16f9d4a
style: pre-commit.ci fixes
pre-commit-ci[bot] Nov 15, 2025
21bd7b4
update the ctest command for module testing
phlptp Nov 15, 2025
d4d99b6
style: pre-commit.ci fixes
pre-commit-ci[bot] Nov 19, 2025
88156f4
update the tests
phlptp Nov 19, 2025
2a9533c
style: pre-commit.ci fixes
pre-commit-ci[bot] Nov 19, 2025
e4035ae
change to ninja generator for test
phlptp Nov 19, 2025
e1268c5
try using an action to get gcc 15
phlptp Nov 19, 2025
75e0a18
update some tests
phlptp Nov 20, 2025
dd8ca49
add ninja install
phlptp Nov 20, 2025
6c43ac2
style: pre-commit.ci fixes
pre-commit-ci[bot] Nov 20, 2025
d171471
update to support cmake 4.2
phlptp Nov 20, 2025
7fd46cb
Apply suggestions from code review
phlptp Nov 21, 2025
a078faa
style: pre-commit.ci fixes
pre-commit-ci[bot] Nov 21, 2025
34dd3ff
Merge branch 'main' into module_testing
phlptp Nov 21, 2025
f4ab712
try making the CLI11 module code changes dependent on C++17 for compi…
phlptp Nov 22, 2025
18f9850
try with static
phlptp Nov 22, 2025
a2148d1
style: pre-commit.ci fixes
pre-commit-ci[bot] Nov 22, 2025
eb6800a
more code cleanup
phlptp Nov 22, 2025
b973307
style: pre-commit.ci fixes
pre-commit-ci[bot] Nov 22, 2025
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
7 changes: 5 additions & 2 deletions .codacy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ engines:
coverage:
enabled: false
cppcheck:
enabled: false
language: c++
enabled: true
options:
suppress:
- missingIncludeSystem

languages:

ignore:
Expand Down
29 changes: 29 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,29 @@ jobs:
- name: Run tests
run: ctest --output-on-failure -L Packaging
working-directory: build

install-module:
name: install module tests
runs-on: ubuntu-latest
container: gcc:15
steps:
- uses: actions/checkout@v4
with:
submodules: true
- uses: ./.github/actions/quick_cmake
with:
cmake-version: "4.2"
- uses: seanmiddleditch/gha-setup-ninja@master
- name: Configure
run: cmake -S . -B build -DCLI11_INSTALL_PACKAGE_TESTS=ON -DCLI11_MODULE_TESTS=ON -DCMAKE_INSTALL_PREFIX=/home/runner/work/install -DCMAKE_CXX_STANDARD=23
- name: Build
run: cmake --build build -j2
- name: install
run: cmake --install build
- name: Run tests
run: ctest --output-on-failure -L Packaging
working-directory: build


cmake-config-ubuntu-2204:
name: CMake config check (Ubuntu 22.04)
Expand Down Expand Up @@ -449,3 +472,9 @@ jobs:
with:
cmake-version: "4.1"
if: success() || failure()

- name: Check CMake 4.2
uses: ./.github/actions/quick_cmake
with:
cmake-version: "4.2"
if: success() || failure()
5 changes: 4 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.14...4.1)
cmake_minimum_required(VERSION 3.14...4.2)
# Note: this is a header only library. If you have an older CMake than 3.14,
# just add the CLI11/include directory and that's all you need to do.

Expand Down Expand Up @@ -65,6 +65,9 @@ endif()
option(CLI11_WARNINGS_AS_ERRORS "Turn all warnings into errors (for CI)")
option(CLI11_SINGLE_FILE "Generate a single header file")
option(CLI11_PRECOMPILED "Generate a precompiled static library instead of a header-only" OFF)
cmake_dependent_option(CLI11_MODULE "Modify some code to support inclusion of CLI11 in a module"
OFF "CMAKE_CXX_STANDARD GREATER_EQUAL 20" OFF)

cmake_dependent_option(CLI11_SANITIZERS "Download the sanitizers CMake config" OFF
"NOT CMAKE_VERSION VERSION_LESS 3.15" OFF)

Expand Down
7 changes: 7 additions & 0 deletions azure-pipelines.yml
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,13 @@ jobs:
vmImage: "ubuntu-latest"
strategy:
matrix:
gcc15_23:
containerImage: gcc:15
cli11.std: 23
cli11.options:
-DCMAKE_CXX_FLAGS="-Wstrict-overflow=5"
-DCLI11_ENABLE_EXTRA_VALIDATORS=1 -DCLI11_MODULE=ON

gcc13_17:
containerImage: gcc:13
cli11.std: 17
Expand Down
28 changes: 15 additions & 13 deletions book/chapters/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -176,19 +176,21 @@ Total Test time (real) = 0.34 sec
For the curious, the CMake options and defaults are listed below. Most options
default to off if CLI11 is used as a subdirectory in another project.

| Option | Description |
| ------------------------------ | -------------------------------------------------------------------------------- |
| `CLI11_SINGLE_FILE=ON` | Build the `CLI11.hpp` file from the sources. Requires Python (version 3 or 2.7). |
| `CLI11_PRECOMPILED=OFF` | generate a precompiled static library instead of header-only |
| `CLI11_SINGLE_FILE_TESTS=OFF` | Run the tests on the generated single file version as well |
| `CLI11_BUILD_DOCS=ON` | build CLI11 documentation and book |
| `CLI11_BUILD_EXAMPLES=ON` | Build the example programs. |
| `CLI11_BUILD_EXAMPLES_JSON=ON` | Build some additional example using json libraries |
| `CLI11_INSTALL=ON` | install CLI11 to the install folder during the install process |
| `CLI11_FULL_INSTALL=ON` | install all CLI11 headers/libraries regardless of other settings |
| `CLI11_FORCE_LIBCXX=OFF` | use libc++ instead of libstdc++ if building with clang on linux |
| `CLI11_CUDA_TESTS=OFF` | build the tests with NVCC |
| `CLI11_BUILD_TESTS=ON` | Build the tests. |
| Option | Description |
| --------------------------------- | -------------------------------------------------------------------------------- |
| `CLI11_SINGLE_FILE=ON` | Build the `CLI11.hpp` file from the sources. Requires Python (version 3 or 2.7). |
| `CLI11_PRECOMPILED=OFF` | Generate a precompiled static library instead of header-only |
| `CLI11_INSTALL_PACKAGE_TESTS=OFF` | Run tests checking the installation |
| `CLI11_MODULE_TEST=OFF` | Run a test checking that CLI11 works with modules |
| `CLI11_SINGLE_FILE_TESTS=OFF` | Run the tests on the generated single file version as well |
| `CLI11_BUILD_DOCS=ON` | Build CLI11 documentation and book |
| `CLI11_BUILD_EXAMPLES=ON` | Build the example programs. |
| `CLI11_BUILD_EXAMPLES_JSON=ON` | Build some additional example using json libraries |
| `CLI11_INSTALL=ON` | Install CLI11 to the install folder during the install process |
| `CLI11_FULL_INSTALL=ON` | Install all CLI11 headers/libraries regardless of other settings |
| `CLI11_FORCE_LIBCXX=OFF` | Use libc++ instead of libstdc++ if building with clang on linux |
| `CLI11_CUDA_TESTS=OFF` | Build the tests with NVCC |
| `CLI11_BUILD_TESTS=ON` | Build the tests. |

[^1]:
Docker is being used to create a pristine disposable environment; there is
Expand Down
7 changes: 7 additions & 0 deletions include/CLI/Macros.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -175,4 +175,11 @@
#else
#define CLI11_INLINE inline
#endif

/** Module inline to support module operations**/
#if defined CLI11_CPP17
#define CLI11_MODULE_INLINE inline
#else
#define CLI11_MODULE_INLINE static
#endif
// [CLI11:macros_hpp:end]
2 changes: 1 addition & 1 deletion include/CLI/StringTools.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ using enums::operator<<;
namespace detail {
/// a constant defining an expected max vector size defined to be a big number that could be multiplied by 4 and not
/// produce overflow for some expected uses
constexpr int expected_max_vector_size{1 << 29};
CLI11_MODULE_INLINE constexpr int expected_max_vector_size{1 << 29};
// Based on http://stackoverflow.com/questions/236129/split-a-string-in-c
/// Split a string by a delim
CLI11_INLINE std::vector<std::string> split(const std::string &s, char delim);
Expand Down
2 changes: 1 addition & 1 deletion include/CLI/TypeTools.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ namespace detail {
enum class enabler : std::uint8_t {};

/// An instance to use in EnableIf
constexpr enabler dummy = {};
CLI11_MODULE_INLINE constexpr enabler dummy = {};
} // namespace detail

/// A copy of enable_if_t from C++14, compatible with C++11.
Expand Down
9 changes: 6 additions & 3 deletions include/CLI/impl/App_inl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1272,15 +1272,18 @@ CLI11_INLINE void App::_process_help_flags(CallbackPriority priority, bool trigg
const Option *help_ptr = get_help_ptr();
const Option *help_all_ptr = get_help_all_ptr();

if(help_ptr != nullptr && help_ptr->count() > 0 && help_ptr->get_callback_priority() == priority)
if(help_ptr != nullptr && help_ptr->count() > 0 && help_ptr->get_callback_priority() == priority) {
trigger_help = true;
if(help_all_ptr != nullptr && help_all_ptr->count() > 0 && help_all_ptr->get_callback_priority() == priority)
}
if(help_all_ptr != nullptr && help_all_ptr->count() > 0 && help_all_ptr->get_callback_priority() == priority) {
trigger_all_help = true;
}

// If there were parsed subcommands, call those. First subcommand wins if there are multiple ones.
if(!parsed_subcommands_.empty()) {
for(const App *sub : parsed_subcommands_)
for(const App *sub : parsed_subcommands_) {
sub->_process_help_flags(priority, trigger_help, trigger_all_help);
}

// Only the final subcommand should call for help. All help wins over help.
} else if(trigger_all_help) {
Expand Down
8 changes: 4 additions & 4 deletions include/CLI/impl/StringTools_inl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,10 +185,10 @@ find_member(std::string name, const std::vector<std::string> names, bool ignore_
return (it != std::end(names)) ? (it - std::begin(names)) : (-1);
}

static const std::string escapedChars("\b\t\n\f\r\"\\");
static const std::string escapedCharsCode("btnfr\"\\");
static const std::string bracketChars{"\"'`[(<{"};
static const std::string matchBracketChars("\"'`])>}");
CLI11_MODULE_INLINE const std::string &escapedChars("\b\t\n\f\r\"\\");
CLI11_MODULE_INLINE const std::string &escapedCharsCode("btnfr\"\\");
CLI11_MODULE_INLINE const std::string &bracketChars("\"'`[(<{");
CLI11_MODULE_INLINE const std::string &matchBracketChars("\"'`])>}");

CLI11_INLINE bool has_escapable_character(const std::string &str) {
return (str.find_first_of(escapedChars) != std::string::npos);
Expand Down
4 changes: 4 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ else()
set(SYSTEM_INCL "SYSTEM")
endif()

if(CLI11_MODULE)
target_compile_definitions(CLI11 ${PUBLIC_OR_INTERFACE} -DCLI11_MODULE=1)
endif()

# Duplicated because CMake adds the current source dir if you don't.
target_include_directories(
CLI11 ${SYSTEM_INCL} ${PUBLIC_OR_INTERFACE} $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
Expand Down
18 changes: 18 additions & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,24 @@ if(CLI11_INSTALL_PACKAGE_TESTS)
set_property(TEST find-package-testsC PROPERTY LABELS Packaging)
set_property(TEST find-package-testsC PROPERTY DEPENDS find-package-testsB)

if(CLI11_MODULE_TESTS)
add_test(
find-package-module
${CMAKE_CTEST_COMMAND}
--build-and-test
"${CMAKE_CURRENT_SOURCE_DIR}/module_test"
"${CMAKE_CURRENT_BINARY_DIR}/module_test"
--build-generator
"Ninja"
--build-options
"-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}"
"-DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}"
"-DCLI11_DIR=${CMAKE_INSTALL_PREFIX}"
${package_test_command})

set_property(TEST find-package-module PROPERTY LABELS Packaging)
endif()

if(NOT MSVC)
# Tests for other CMake projects using the package_config files
add_test(
Expand Down
25 changes: 25 additions & 0 deletions tests/module_test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
cmake_minimum_required(VERSION 3.14...4.2)

project(CLI11-module-test)

include(CTest)

if(CLI11_DIR)
set(CMAKE_PREFIX_PATH ${CLI11_DIR})
endif()

set(CMAKE_CXX_STANDARD 23)
Copy link
Collaborator

Choose a reason for hiding this comment

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

This could be 20 as well?

# Test the CLI11 CMake package config
find_package(CLI11 2.5 REQUIRED)

# Test the target
add_executable(module-test module_test.cpp)

target_sources(module-test PUBLIC FILE_SET cmodule TYPE CXX_MODULES FILES cmodule.ixx)

target_link_libraries(module-test CLI11::CLI11)
target_compile_definitions(module-test PUBLIC -DCLI11_MODULE=1)
target_compile_options(module-test PUBLIC -fmodules-ts)

add_test(NAME module-test1 COMMAND module-test one)
set_property(TEST module-test1 PROPERTY PASS_REGULAR_EXPRESSION "OK: export module")
21 changes: 21 additions & 0 deletions tests/module_test/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2024 scivision

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
20 changes: 20 additions & 0 deletions tests/module_test/cmodule.ixx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Copyright (c) 2024 scivision
// Copyright (c) 2025 University of Cincinnati, developed by Henry Schreiner
// under NSF AWARD 1414736 and by the respective contributors.
// All rights reserved.
//
// SPDX-License-Identifier: MIT

// modified from https://github.com/iTrooz/CppModules/blob/cli11 for use in CLI11 tests

module;

#include <CLI/CLI.hpp>

export module cmodule;

export void foo(CLI::App *app) {}

export int add(int a, int b) { return a + b; }

export int subtract(int a, int b) { return a - b; }
30 changes: 30 additions & 0 deletions tests/module_test/module_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) 2024 scivision
// Copyright (c) 2025 University of Cincinnati, developed by Henry Schreiner
// under NSF AWARD 1414736 and by the respective contributors.
// All rights reserved.
//
// SPDX-License-Identifier: MIT

// modified from https://github.com/iTrooz/CppModules/blob/cli11 for use in CLI11 tests

#include <cassert>
#include <cstdio>
#include <cstdlib>

import cmodule;

int main() {
int a = 1;
int b = 2;

int absum = add(a, b);
int abdif = subtract(a, b);

assert(a + b == absum);
assert(a - b == abdif);

// used this instead of <iostream> to work with older compilers that may choke on <iostream> implicit includes
printf("OK: export module\n");

return EXIT_SUCCESS;
}