-
Notifications
You must be signed in to change notification settings - Fork 2
feat: add extern "C" guards to public headers #128
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
grzanka
wants to merge
5
commits into
main
Choose a base branch
from
claude/libdedx-deps-review-beQBi
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
78b8753
feat: add extern "C" guards to public headers
grzanka ef43ab5
feat: add extern "C" guards to remaining public headers
grzanka aea9642
test: add C++ example consumers with cross-platform CI
grzanka b33c533
docs: add examples README with copy-paste build/run instructions
grzanka 522cd4b
ci: restrict GITHUB_TOKEN permissions in cpp-examples workflow
grzanka File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| name: C++ Examples | ||
|
|
||
| # Builds the C++ example consumers and runs their tests on Linux, Windows and | ||
| # macOS. This guards the public headers' extern "C" guards: the examples | ||
| # include dedx.h / dedx_tools.h / dedx_wrappers.h from C++ translation units | ||
| # and link the C library, so a regression in the guards breaks this workflow. | ||
|
|
||
| on: | ||
| push: | ||
| branches: [main] | ||
| pull_request: | ||
| workflow_dispatch: | ||
|
|
||
| # Build/test only: the token needs no more than read access to the checkout. | ||
| permissions: | ||
| contents: read | ||
|
|
||
| jobs: | ||
| cpp-examples: | ||
| name: ${{ matrix.os }} | ||
| runs-on: ${{ matrix.os }} | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| os: [ubuntu-latest, windows-latest, macos-latest] | ||
|
|
||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v6 | ||
|
|
||
| - name: Tool versions | ||
| run: | | ||
| cmake --version | ||
| cmake -E echo "Generator/compiler resolved at configure time" | ||
|
|
||
| - name: Configure | ||
| run: > | ||
| cmake -S . -B build | ||
| -DCMAKE_BUILD_TYPE=Release | ||
| -DDEDX_BUILD_EXAMPLES=ON | ||
| -DDEDX_BUILD_CXX_EXAMPLES=ON | ||
| -DDEDX_BUILD_TESTS=OFF | ||
|
|
||
| - name: Build | ||
| run: cmake --build build --config Release --parallel | ||
|
|
||
| - name: Run C++ example tests | ||
| run: ctest --test-dir build -C Release -R dedx_cpp --output-on-failure | ||
|
grzanka marked this conversation as resolved.
Fixed
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,106 @@ | ||
| # libdedx examples | ||
|
|
||
| Small, self-contained programs that show how to call libdedx. The C programs | ||
| live in this directory; the C++ programs (which consume the public headers | ||
| through their `extern "C"` guards) live in [`cpp/`](cpp/). | ||
|
|
||
| Every code block below is a **single command** — use the copy button and run | ||
| them one at a time, in order. All paths are relative to the repository root. | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| - CMake 3.21 or newer | ||
| - A C11 compiler (and a C++17 compiler for the `cpp/` examples) | ||
|
|
||
| ## 1. Configure | ||
|
|
||
| ```bash | ||
| cmake --preset debug | ||
| ``` | ||
|
|
||
| ## 2. Build everything (library + examples) | ||
|
|
||
| ```bash | ||
| cmake --build --preset debug | ||
| ``` | ||
|
|
||
| ## 3. Run the C examples | ||
|
|
||
| ```bash | ||
| ./build/examples/dedx_example | ||
| ``` | ||
|
|
||
| ```bash | ||
| ./build/examples/dedx_list | ||
| ``` | ||
|
|
||
| ```bash | ||
| ./build/examples/dedx_use_wrappers | ||
| ``` | ||
|
|
||
| ```bash | ||
| ./build/examples/dedx_bethe | ||
| ``` | ||
|
|
||
| ```bash | ||
| ./build/examples/dedx_csda | ||
| ``` | ||
|
|
||
| ```bash | ||
| ./build/examples/dedx_custom_compound | ||
| ``` | ||
|
|
||
| ## 4. Run the C++ examples | ||
|
|
||
| ```bash | ||
| ./build/examples/cpp/dedx_cpp_core | ||
| ``` | ||
|
|
||
| ```bash | ||
| ./build/examples/cpp/dedx_cpp_wrappers | ||
| ``` | ||
|
|
||
| ## 5. Use the `getdedx` command-line tool | ||
|
|
||
| Look up PSTAR stopping power for a proton in water at 100 MeV/nucl: | ||
|
|
||
| ```bash | ||
| ./build/examples/getdedx 2 1 276 100 | ||
| ``` | ||
|
|
||
| ## Run examples as a test suite | ||
|
|
||
| Run every example test: | ||
|
|
||
| ```bash | ||
| ctest --preset debug --output-on-failure | ||
| ``` | ||
|
|
||
| Run only the C++ example tests: | ||
|
|
||
| ```bash | ||
| ctest --preset debug --output-on-failure -R dedx_cpp | ||
| ``` | ||
|
|
||
| ## Building without the C++ examples | ||
|
|
||
| If you have no C++ compiler, turn the C++ examples off at configure time: | ||
|
|
||
| ```bash | ||
| cmake --preset debug -DDEDX_BUILD_CXX_EXAMPLES=OFF | ||
| ``` | ||
|
|
||
| ## Windows note | ||
|
|
||
| The Visual Studio generator is multi-config, so the binaries land in a | ||
| per-config subfolder. Build with an explicit config: | ||
|
|
||
| ```bash | ||
| cmake --build build --config Release | ||
| ``` | ||
|
|
||
| Then run from the matching folder, e.g.: | ||
|
|
||
| ```bash | ||
| ./build/examples/cpp/Release/dedx_cpp_core.exe | ||
| ``` |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| # C++ example consumers. | ||
| # | ||
| # These demonstrate that the public libdedx headers can be included and linked | ||
| # from C++ thanks to their extern "C" guards. The library remains C-only, so | ||
| # C++ is enabled lazily here and the whole subdirectory is skipped when no C++ | ||
| # compiler is available. | ||
| include(CheckLanguage) | ||
| check_language(CXX) | ||
| if(NOT CMAKE_CXX_COMPILER) | ||
| message(STATUS "No C++ compiler found; skipping C++ example consumers") | ||
| return() | ||
| endif() | ||
| enable_language(CXX) | ||
|
|
||
| set(CMAKE_CXX_STANDARD 17) | ||
| set(CMAKE_CXX_STANDARD_REQUIRED ON) | ||
| set(CMAKE_CXX_EXTENSIONS OFF) | ||
|
|
||
| set(cpp_examples dedx_cpp_core dedx_cpp_wrappers) | ||
|
|
||
| foreach(example ${cpp_examples}) | ||
| add_executable(${example} ${example}.cpp) | ||
| # Linking the `dedx` target transitively pulls in its PUBLIC dependencies | ||
| # (e.g. the math library on Unix), so no per-platform handling is needed. | ||
| target_link_libraries(${example} PRIVATE dedx) | ||
| if(MSVC) | ||
| target_compile_options(${example} PRIVATE /W4 /permissive-) | ||
| else() | ||
| target_compile_options(${example} PRIVATE -Wall -Wextra) | ||
| endif() | ||
| add_test(NAME ${example} COMMAND ${example}) | ||
| endforeach() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| // Core (stateful) libdedx API consumed from C++. | ||
| // | ||
| // Builds a proton-in-water stopping-power / CSDA-range table using the RAII | ||
| // helpers, std::vector and exception-based error handling. Demonstrates that | ||
| // dedx.h and dedx_tools.h link cleanly into a C++ program now that the public | ||
| // headers carry extern "C" guards. | ||
| #include <cstdlib> | ||
| #include <dedx.h> | ||
| #include <dedx_tools.h> | ||
| #include <iomanip> | ||
| #include <iostream> | ||
| #include <vector> | ||
|
|
||
| #include "dedx_raii.hpp" | ||
|
|
||
| int main() { | ||
| try { | ||
| auto ws = dedx::make_workspace(1); | ||
|
|
||
| auto cfg = dedx::make_config(); | ||
| cfg->program = DEDX_PSTAR; | ||
| cfg->ion = DEDX_PROTON; | ||
| cfg->ion_a = 1; // nucleon number, required by dedx_get_csda | ||
| cfg->target = DEDX_WATER; | ||
|
|
||
| int err = DEDX_OK; | ||
| dedx_load_config(ws.get(), cfg.get(), &err); | ||
| dedx::check(err, "dedx_load_config"); | ||
|
|
||
| const std::vector<float> energies = {1.0f, 5.0f, 10.0f, 50.0f, 100.0f, 250.0f}; | ||
|
|
||
| std::cout << "Proton stopping power & CSDA range in liquid water (PSTAR)\n"; | ||
| std::cout << " E [MeV/nucl] dE/dx [MeV cm^2/g] CSDA [g/cm^2]\n"; | ||
| std::cout << std::fixed << std::setprecision(4); | ||
|
|
||
| for (const float e : energies) { | ||
| const float stp = dedx_get_stp(ws.get(), cfg.get(), e, &err); | ||
| dedx::check(err, "dedx_get_stp"); | ||
|
|
||
| const double csda = dedx_get_csda(ws.get(), cfg.get(), e, &err); | ||
| dedx::check(err, "dedx_get_csda"); | ||
|
|
||
| std::cout << std::setw(14) << e << std::setw(21) << stp << std::setw(16) << csda << '\n'; | ||
| } | ||
|
|
||
| return EXIT_SUCCESS; | ||
| } catch (const dedx::error &ex) { | ||
| std::cerr << "libdedx error: " << ex.what() << '\n'; | ||
| return EXIT_FAILURE; | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,74 @@ | ||
| // Stateless wrapper + tools libdedx APIs consumed from C++. | ||
| // | ||
| // Reads the program's default tabulated grid, evaluates a custom energy grid | ||
| // in one batched call, and converts mass stopping power to linear stopping | ||
| // power — all backed by std::vector. Exercises dedx_wrappers.h and | ||
| // dedx_tools.h from a C++ translation unit. | ||
| #include <cstddef> | ||
| #include <cstdlib> | ||
| #include <dedx.h> | ||
| #include <dedx_tools.h> | ||
| #include <dedx_wrappers.h> | ||
| #include <iomanip> | ||
| #include <iostream> | ||
| #include <vector> | ||
|
|
||
| #include "dedx_raii.hpp" | ||
|
|
||
| int main() { | ||
| try { | ||
| constexpr int program = DEDX_PSTAR; | ||
| constexpr int ion = DEDX_PROTON; | ||
| constexpr int target = DEDX_WATER_LIQUID; | ||
|
|
||
| // 1) Default tabulated grid shipped with the program. | ||
| const int n = dedx_get_stp_table_size(program, ion, target); | ||
| if (n <= 0) { | ||
| std::cerr << "no tabulated data for this program/ion/target\n"; | ||
| return EXIT_FAILURE; | ||
| } | ||
|
|
||
| std::vector<float> grid_e(static_cast<std::size_t>(n)); | ||
| std::vector<float> grid_stp(static_cast<std::size_t>(n)); | ||
| // Returns 0 on success / negative on error; the point count is `n`. | ||
| if (dedx_fill_default_energy_stp_table(program, ion, target, grid_e.data(), grid_stp.data()) < 0) { | ||
| std::cerr << "dedx_fill_default_energy_stp_table failed\n"; | ||
| return EXIT_FAILURE; | ||
| } | ||
| std::cout << "Default PSTAR grid: " << n << " points, " << grid_e.front() << " - " << grid_e.back() | ||
| << " MeV/nucl\n"; | ||
|
|
||
| // 2) Evaluate an arbitrary energy grid in a single batched call. | ||
| const std::vector<float> energies = {2.0f, 20.0f, 200.0f}; | ||
| std::vector<float> stps(energies.size()); | ||
| dedx::check( | ||
| dedx_get_stp_table(program, ion, target, static_cast<int>(energies.size()), energies.data(), stps.data()), | ||
| "dedx_get_stp_table"); | ||
|
|
||
| // 3) Convert mass stopping power [MeV cm^2/g] to linear units. For | ||
| // liquid water (rho = 1 g/cm^3) the MeV/cm value coincides | ||
| // numerically with the mass value, so keV/um is shown too to make | ||
| // the unit change visible. | ||
| const auto convert = [&](int to_unit) { | ||
| std::vector<float> out(stps.size()); | ||
| dedx::check( | ||
| convert_units(DEDX_MEVCM2G, to_unit, target, static_cast<int>(stps.size()), stps.data(), out.data()), | ||
| "convert_units"); | ||
| return out; | ||
| }; | ||
| const std::vector<float> stps_mevcm = convert(DEDX_MEVCM); | ||
| const std::vector<float> stps_kevum = convert(DEDX_KEVUM); | ||
|
|
||
| std::cout << " E [MeV/nucl] dE/dx [MeV cm^2/g] dE/dx [MeV/cm] dE/dx [keV/um]\n"; | ||
| std::cout << std::fixed << std::setprecision(4); | ||
| for (std::size_t i = 0; i < energies.size(); ++i) { | ||
| std::cout << std::setw(14) << energies[i] << std::setw(21) << stps[i] << std::setw(16) << stps_mevcm[i] | ||
| << std::setw(16) << stps_kevum[i] << '\n'; | ||
| } | ||
|
|
||
| return EXIT_SUCCESS; | ||
| } catch (const dedx::error &ex) { | ||
| std::cerr << "libdedx error: " << ex.what() << '\n'; | ||
| return EXIT_FAILURE; | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.