Skip to content

255 organize odeint as stand alone library#256

Merged
GeorgGrassler merged 3 commits intomainfrom
255-organize-odeint-as-stand-alone-library
Mar 20, 2026
Merged

255 organize odeint as stand alone library#256
GeorgGrassler merged 3 commits intomainfrom
255-organize-odeint-as-stand-alone-library

Conversation

@GeorgGrassler
Copy link
Copy Markdown
Contributor

No description provided.

The location of mod needs to be specified explicit if used outside the libneo build. We also need to explicit compile odeint with omp if it needs to be run by e.g. libneo tests in that mode.
@GeorgGrassler GeorgGrassler linked an issue Mar 5, 2026 that may be closed by this pull request
@qodo-code-review
Copy link
Copy Markdown
Contributor

Review Summary by Qodo

Organize odeint as standalone library module

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Reorganize odeint as independent library module
• Move odeint source to dedicated src/odeint directory
• Create standalone CMakeLists.txt for odeint compilation
• Add explicit OpenMP support for odeint library
Diagram
flowchart LR
  A["CMakeLists.txt"] -->|"add_subdirectory"| B["src/odeint/CMakeLists.txt"]
  C["CMakeSources.in"] -->|"remove odeint_allroutines.f90"| D["src/odeint/odeint_allroutines.f90"]
  B -->|"create library"| E["odeint STATIC library"]
  E -->|"link to neo"| F["neo library"]
  E -->|"conditional OpenMP"| G["OpenMP::OpenMP_Fortran"]
Loading

Grey Divider

File Changes

1. CMakeLists.txt ⚙️ Configuration changes +1/-0

Add odeint subdirectory to build system

• Added add_subdirectory(src/odeint) to build odeint as independent module
• Positioned after interpolate and before field subdirectories

CMakeLists.txt


2. CMakeSources.in ⚙️ Configuration changes +1/-1

Move odeint from sources to linked library

• Removed src/odeint_allroutines.f90 from neo library sources
• Added odeint to neo library's public link libraries
• Odeint now linked as external library instead of direct source

CMakeSources.in


3. src/odeint/CMakeLists.txt ⚙️ Configuration changes +15/-0

Create standalone odeint library build configuration

• Created new CMakeLists.txt for odeint as standalone STATIC library
• Configured Fortran module directory to build directory
• Added conditional OpenMP support when ENABLE_OPENMP is set
• Exposed module directory via public include interface
• Created LIBNEO::odeint alias for library

src/odeint/CMakeLists.txt


View more (1)
4. src/odeint/odeint_allroutines.f90 Additional files +0/-0

...

src/odeint/odeint_allroutines.f90


Grey Divider

Qodo Logo

@qodo-code-review
Copy link
Copy Markdown
Contributor

qodo-code-review bot commented Mar 5, 2026

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0)

Grey Divider


Action required

1. ODEINT modules not installed 🐞 Bug ⛯ Reliability
Description
odeint writes its .mod files to src/odeint's binary dir instead of the project-wide
${CMAKE_Fortran_MODULE_DIRECTORY}; existing install/copy steps that package modules from the
global module directory will omit ODEINT modules, breaking downstream compilation against installed
artifacts.
Code

src/odeint/CMakeLists.txt[R11-14]

+set_target_properties(odeint PROPERTIES
+      Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
+target_include_directories(odeint PUBLIC
+    $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
Evidence
The repo establishes a single global module output directory (${binary}/include) and at least one
install step copies modules from that directory. The new odeint target overrides its module output
location to its local binary directory, so its .mod files won’t be present in the global module
directory that gets installed/copied. There are also in-repo consumers that `use
odeint_allroutines_sub, so missing .mod` files in the packaged include dir would break compilation
for those consumers outside this build tree.

CMakeLists.txt[61-65]
src/odeint/CMakeLists.txt[11-14]
src/hdf5_tools/CMakeLists.txt[31-37]
src/poincare.f90[124-133]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`odeint` currently emits Fortran `.mod` files into its local binary dir (`src/odeint` build dir) rather than the project-wide `${CMAKE_Fortran_MODULE_DIRECTORY}` used elsewhere. Existing module packaging/install steps that copy `${CMAKE_Fortran_MODULE_DIRECTORY}` will therefore omit ODEINT modules, breaking downstream compilation against installed artifacts.

## Issue Context
The root build sets a global module directory (`${binary}/include`). Other parts of the build/install logic copy modules from that directory.

## Fix Focus Areas
- src/odeint/CMakeLists.txt[11-14]
- CMakeLists.txt[61-65]
- src/hdf5_tools/CMakeLists.txt[31-37]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Standalone target not exportable 🐞 Bug ⛯ Reliability
Description
The new standalone odeint target only provides a BUILD_INTERFACE include dir and has no
install/export rules; if it’s intended to be consumed outside the build tree (as implied by the PR
goal), consumers won’t be able to install()/package and then find_package()/use it reliably.
Code

src/odeint/CMakeLists.txt[R13-15]

+target_include_directories(odeint PUBLIC
+    $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
+add_library(LIBNEO::odeint ALIAS odeint)
Evidence
odeint exposes module paths only for in-build consumption. The repository already has examples of
installing targets/modules (e.g., hdf5_tools), suggesting that installability matters for at least
some sub-libraries. Without an INSTALL_INTERFACE include dir and install rules for the archive and
modules, odeint can’t be consumed cleanly from an install prefix.

src/odeint/CMakeLists.txt[13-15]
src/hdf5_tools/CMakeLists.txt[31-37]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`odeint` is structured as a standalone library target but is only usable from the build tree. It lacks install rules and an `INSTALL_INTERFACE` include dir for its module output, making it hard/impossible to consume from an installed prefix.

## Issue Context
Other parts of the repo already use `install(TARGETS ...)` and install module directories, which implies installed consumption exists for at least some components.

## Fix Focus Areas
- src/odeint/CMakeLists.txt[1-15]
- src/hdf5_tools/CMakeLists.txt[31-37]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +11 to +14
set_target_properties(odeint PROPERTIES
Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
target_include_directories(odeint PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Action required

1. Odeint modules not installed 🐞 Bug ⛯ Reliability

odeint writes its .mod files to src/odeint's binary dir instead of the project-wide
${CMAKE_Fortran_MODULE_DIRECTORY}; existing install/copy steps that package modules from the
global module directory will omit ODEINT modules, breaking downstream compilation against installed
artifacts.
Agent Prompt
## Issue description
`odeint` currently emits Fortran `.mod` files into its local binary dir (`src/odeint` build dir) rather than the project-wide `${CMAKE_Fortran_MODULE_DIRECTORY}` used elsewhere. Existing module packaging/install steps that copy `${CMAKE_Fortran_MODULE_DIRECTORY}` will therefore omit ODEINT modules, breaking downstream compilation against installed artifacts.

## Issue Context
The root build sets a global module directory (`${binary}/include`). Other parts of the build/install logic copy modules from that directory.

## Fix Focus Areas
- src/odeint/CMakeLists.txt[11-14]
- CMakeLists.txt[61-65]
- src/hdf5_tools/CMakeLists.txt[31-37]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

this was done to not rely on CMAKE_Fortran_MODULE_DIRECTORY to be set by libneo if odeint is build independant. Thoughts?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Question:

this was done to not rely on CMAKE_Fortran_MODULE_DIRECTORY to be set by libneo if odeint is build independant. Thoughts?

Answer:

You can steer Qodo Merge’s /improve suggestions to explicitly account for “odeint can be built standalone” and avoid recommendations that assume ${CMAKE_Fortran_MODULE_DIRECTORY} is always set.

Add a repo-level instruction for the improve tool:

[pr_code_suggestions]
extra_instructions = """\
When reviewing CMake/Fortran module installation issues:
- Assume subprojects (like odeint) may be built standalone, so do NOT assume CMAKE_Fortran_MODULE_DIRECTORY is always set by a parent project.
- If suggesting to use CMAKE_Fortran_MODULE_DIRECTORY, require a safe fallback behavior when it is unset (e.g., set a sensible default module dir or guard logic), and preserve standalone-build correctness.
- Prefer solutions that keep install/packaging of .mod files correct both when embedded in libneo and when built independently.
"""

If you want this guidance only for a single PR run, you can pass it inline:

/improve --pr_code_suggestions.extra_instructions="(same text as above)"

If you share which platform you’re using (GitHub App vs Action vs CLI) and whether this feedback is coming from /improve (code suggestions) or /review, I can suggest the most appropriate place to set it (wiki vs local vs global .pr_agent.toml).

Relevant Sources:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Action required
  1. Odeint modules not installed 🐞 Bug ⛯ Reliability

odeint writes its .mod files to src/odeint's binary dir instead of the project-wide
${CMAKE_Fortran_MODULE_DIRECTORY}; existing install/copy steps that package modules from the
global module directory will omit ODEINT modules, breaking downstream compilation against installed
artifacts.

Agent Prompt

this was done to not rely on CMAKE_Fortran_MODULE_DIRECTORY to be set by libneo if odeint is build independant. Thoughts?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Question:

Action > > 1. Odeint modules not installed 🐞 Bug ⛯ Reliability > > odeint writes its .mod files to src/odeint's binary dir instead of the project-wide > ${CMAKE_Fortran_MODULE_DIRECTORY}; existing install/copy steps that package modules from the > global module directory will omit ODEINT modules, breaking downstream compilation against installed > artifacts. > > Agent Prompt this was done to not rely on CMAKE_Fortran_MODULE_DIRECTORY to be set by libneo if odeint is build independant. Thoughts?

Answer:

You can steer Qodo Merge’s /improve (code suggestions) to not assume a parent project sets CMAKE_Fortran_MODULE_DIRECTORY, and to require a safe fallback that preserves standalone builds.

Add repo-level guidance for the improve tool in .pr_agent.toml (wiki or repo root):

[pr_code_suggestions]
extra_instructions = """\
When reviewing CMake/Fortran module (.mod) output+install issues:
- Assume subprojects (like odeint) may be built standalone, so do NOT assume CMAKE_Fortran_MODULE_DIRECTORY is set by a parent project.
- If suggesting to use CMAKE_Fortran_MODULE_DIRECTORY, require a safe fallback when it is unset (e.g., set a sensible default module dir or guard logic).
- Prefer solutions that keep packaging/install of .mod files correct both when embedded in a parent build and when built independently.
"""

If you only want this for a single run, pass it inline:

/improve --pr_code_suggestions.extra_instructions="(same text as above)"

If you tell me which platform you use (GitHub App vs GitHub Action vs CLI) I can suggest the best place to store this (wiki vs local .pr_agent.toml vs action env vars).

Relevant Sources:

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

/ask

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Those lines are doing the right thing for a Fortran static library that produces .mod files:

  • Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
    Ensures all module outputs for target odeint are written to the target’s build dir. This avoids scattering .mod files and makes downstream consumption predictable.

  • target_include_directories(odeint PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)
    Exposes that module directory to consumers when building from the build tree, so targets that target_link_libraries(... odeint) can find use <module> .mod files.

A couple of suggested tweaks/considerations:

  • Install/export support: if you ever plan to install(TARGETS odeint EXPORT ...), you’ll likely also want an INSTALL_INTERFACE include dir and to install the .mod files, e.g.
    • target_include_directories(odeint PUBLIC $<BUILD_INTERFACE:...> $<INSTALL_INTERFACE:include>)
    • plus install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ DESTINATION include FILES_MATCHING PATTERN "*.mod") (or better: use a dedicated module install dir).
  • Multi-config generators (Visual Studio, Xcode): ${CMAKE_CURRENT_BINARY_DIR} is fine, but module output may collide across configs unless CMake places them per-config. If you hit issues, consider a config-specific path like ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG> for the module dir.

If this library is only intended for in-tree builds right now, the current setup is solid.

Copy link
Copy Markdown
Contributor Author

@GeorgGrassler GeorgGrassler Mar 5, 2026

Choose a reason for hiding this comment

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

Those lines are doing the right thing for a Fortran static library that produces .mod files:

* `Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}`
  Ensures all module outputs for target `odeint` are written to the target’s build dir. This avoids scattering `.mod` files and makes downstream consumption predictable.

* `target_include_directories(odeint PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>)`
  Exposes that module directory to consumers _when building from the build tree_, so targets that `target_link_libraries(... odeint)` can find `use <module>` `.mod` files.

A couple of suggested tweaks/considerations:

* **Install/export support**: if you ever plan to `install(TARGETS odeint EXPORT ...)`, you’ll likely also want an `INSTALL_INTERFACE` include dir and to install the `.mod` files, e.g.
  
  * `target_include_directories(odeint PUBLIC $<BUILD_INTERFACE:...> $<INSTALL_INTERFACE:include>)`
  * plus `install(DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/ DESTINATION include FILES_MATCHING PATTERN "*.mod")` (or better: use a dedicated module install dir).

* **Multi-config generators** (Visual Studio, Xcode): `${CMAKE_CURRENT_BINARY_DIR}` is fine, but module output may collide across configs unless CMake places them per-config. If you hit issues, consider a config-specific path like `${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>` for the module dir.

If this library is only intended for in-tree builds right now, the current setup is solid.

/ask But do you think that this current approach is okay then?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes—this is a correct and common setup for an in-tree Fortran target that produces .mod files.

  • Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} keeps module outputs centralized (and avoids polluting other build dirs).
  • target_include_directories(... $<BUILD_INTERFACE:...>) is the right way to make dependents find those .mod files during the same build when they link to odeint.

A couple small, practical caveats to consider (only if they apply to your project):

  • Multi-config generators: If you build multiple configs into the same binary dir (VS/Xcode), .mod collisions can happen. If you support those, you may want:
    • Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/$<CONFIG>
    • and mirror that in the BUILD_INTERFACE include dir.
  • Install/export: If you’re not installing/exporting odeint yet, skipping INSTALL_INTERFACE and module installation is totally fine. If you ever do, you’ll need to add install rules for .mod and an INSTALL_INTERFACE include path.

So: for “stand-alone library but used from the build tree” (your current scope), this approach is okay as-is.

@GeorgGrassler
Copy link
Copy Markdown
Contributor Author

GeorgGrassler commented Mar 5, 2026

@marjohma @phizenz @jonatanschatzlmayr

I have finished my modifications of odeint. First things first: The failing tests where failing before my change already. Please test on your end if on a same named branch 255-organize-odeint-as-stand-alone-library

stil run e.g. start your codes test suit for this version of libneo if your project depends on libneo. If you are sure that your code has no dependancy to libneo, just mark it off in the list. I will check

in the meantime.

image

In the CI check, only a shallow copy is used, so `git tag` does not
return anything and the latest commit on the checkout branch is used
i.e. the check is tautologic. Getting the tags from the remote origin
and fetching it, makes the golden record accessible also in a shallow
clone without local tags.
@GeorgGrassler
Copy link
Copy Markdown
Contributor Author

GeorgGrassler commented Mar 18, 2026

@marjohma thank you for pointing out the CI issue. I did indeed "break" the CI test, but it turns out it was already "broken" (i.e. the CI check had problems with how it checksout the repo), but did still pass until I changed the folder structure. Basically, in the CI pipeline, libneo is only checkout as a shallow clone, that has no tags available. So it never fetches the actual golden record commit, but just uses the latest commit in the shallow clone. I have changed that now in the test/odeint/fetch_golden_record.sh it gets the golden record tag from the remote repo main (origin), so that it also works in shallow copies.

Sidenote: the failing tests that I mentioned previously, only appear in my local execution and they appear even if I return to the main branch.

image

TD;LR: The changes seem to not break libneo, but there are some issues with our local setup that I noticed, but are neither introduced/nor fixed by my changes (besides the shallow copy* issue mentioned).

@GeorgGrassler GeorgGrassler merged commit 08cd0cb into main Mar 20, 2026
7 of 12 checks passed
@GeorgGrassler GeorgGrassler deleted the 255-organize-odeint-as-stand-alone-library branch March 20, 2026 11:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

organize: odeint as stand-alone library

1 participant