Skip to content

Fix symbol visibility and add checks#1526

Open
arhag23 wants to merge 6 commits into
NVIDIA:mainfrom
arhag23:fix-symbol-visibility-2
Open

Fix symbol visibility and add checks#1526
arhag23 wants to merge 6 commits into
NVIDIA:mainfrom
arhag23:fix-symbol-visibility-2

Conversation

@arhag23

@arhag23 arhag23 commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Description

Updates CMake code to build with hidden visibility. Adds explicit exports for symbols that should be visible in the shared library. Adds a separate static library for use with the tests which require access to the hidden symbols. Adds a CI check for ensuring no symbols from dependencies and implementation details are leaking.

Issue

Closes #1213
Builds off #1215 which can be closed after this is merged

Checklist

  • I am familiar with the Contributing Guidelines.
  • Testing
    • New or existing tests cover these changes
    • Added tests
    • Created an issue to follow-up
    • NA
  • Documentation
    • The documentation is up to date with these changes
    • Added new documentation
    • NA

@arhag23 arhag23 requested review from a team as code owners July 7, 2026 21:29
@coderabbitai

coderabbitai Bot commented Jul 7, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: a37e0162-6dfd-4f5c-a340-81032f906647

📥 Commits

Reviewing files that changed from the base of the PR and between 9a23ba5 and 75773da.

📒 Files selected for processing (3)
  • ci/check_symbols.sh
  • cpp/CMakeLists.txt
  • cpp/src/pdlp/solve.cu
🚧 Files skipped from review as they are similar to previous changes (1)
  • ci/check_symbols.sh

📝 Walkthrough

Walkthrough

This PR adds export visibility controls for public C++/C APIs, hides default symbols in the libcuopt build, exports selected explicit template instantiations, adds a symbol-leak CI check, and updates tests to link the static target.

Changes

Symbol Visibility Hiding

Layer / File(s) Summary
Export macro and build refactor
cpp/include/cuopt/export.hpp, cpp/CMakeLists.txt
Adds CUOPT_EXPORT and restructures the build around hidden-visibility object, static, and shared targets.
Public API visibility annotations
cpp/include/cuopt/..., cpp/src/math_optimization/solution_reader.hpp, cpp/src/utilities/logger.hpp
Applies export visibility to public namespaces and C API declarations.
Explicit template instantiation exports
cpp/src/grpc/..., cpp/src/io/..., cpp/src/math_optimization/..., cpp/src/mip_heuristics/..., cpp/src/pdlp/..., cpp/src/routing/...
Marks selected explicit template instantiations with CUOPT_EXPORT.
Symbol leak validation
ci/check_symbols.sh, conda/recipes/libcuopt/recipe.yaml
Scans installed dynamic symbols for configured internal patterns and runs the check during packaging.
Test linkage updates
cpp/tests/...
Links internal test targets against cuopt_static while retaining shared-library checks where required.

Estimated code review effort: 4 (Complex) | ~60 minutes

Suggested labels: breaking, improvement

Suggested reviewers: tmckayus, mlubin, kaatish, akifcorduk

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately reflects the main changes: symbol visibility fixes and added checks.
Description check ✅ Passed The description matches the changeset and summarizes the visibility, export, static library, and CI check work.
Linked Issues check ✅ Passed The changes address #1213 by hiding symbols by default, exporting public APIs, adding a static test library, and adding symbol checks.
Out of Scope Changes check ✅ Passed The listed changes all support symbol-visibility hardening, export management, test linkage, or symbol checking.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
cpp/include/cuopt/routing/routing_structures.hpp (1)

18-19: 🔒 Security & Privacy | 🔵 Trivial | 💤 Low value

Keep cuopt::routing::detail hidden
namespace CUOPT_EXPORT routing makes the nested detail helpers part of the exported surface. If they’re internal-only, hide that namespace explicitly (or move it outside the exported namespace) so future out-of-line definitions don’t become ABI-visible.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@cpp/include/cuopt/routing/routing_structures.hpp` around lines 18 - 19, The
exported routing namespace is exposing internal detail helpers through the
public ABI. Update the namespace declaration around cuopt::routing in
routing_structures.hpp so that detail stays hidden, either by removing the
export from the enclosing routing namespace or by placing detail outside the
exported namespace; use the cuopt::routing and cuopt::routing::detail symbols to
keep internal-only helpers out of the exported surface.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@ci/check_symbols.sh`:
- Around line 36-46: The forbidden-symbol check in check_symbols.sh is missing
Abseil coverage, so leaked strong absl:: symbols can pass unnoticed. Update the
patterns array in the symbol-check script to include an absl:: entry alongside
the existing cub::, thrust::, grpc::, and other namespaces. Keep the change
focused on the patterns list so the existing symbol filtering logic continues to
work unchanged.

In `@conda/recipes/libcuopt/recipe.yaml`:
- Around line 108-110: The symbol-check step in the libcuopt build recipe is
missing the toolchain dependency needed by ci/check_symbols.sh, so the check can
fail in a clean environment. Update the output build environment for the
libcuopt recipe to include binutils alongside cmake and stdlib("c"), since
check_symbols.sh relies on readelf and c++filt. Make this change in the recipe
section that defines the libcuopt output build requirements so the symbol
verification step always has the required tools available.

In `@cpp/CMakeLists.txt`:
- Around line 601-638: `cuopt_static` is used outside the `if(BUILD_TESTS)`
block even though it is only created there. Move the
`target_link_libraries(cuopt_static PRIVATE $<TARGET_FILE:PSLP>)` and
`add_dependencies(cuopt_static PSLP)` calls inside the same `BUILD_TESTS` guard
(or otherwise guard them on target existence) so CMake does not reference a
non-existent target when tests are disabled.

In `@cpp/include/cuopt/grpc/grpc_client_env.hpp`:
- Around line 10-11: Add the missing cuopt export header to make
grpc_client_env.hpp self-contained, since the CUOPT_EXPORT symbol is used in the
namespace declaration but is only brought in transitively today. Update the
includes in grpc_client_env.hpp so it directly includes cuopt/export.hpp
alongside grpc_client.hpp, ensuring the header compiles on its own regardless of
include order.

---

Nitpick comments:
In `@cpp/include/cuopt/routing/routing_structures.hpp`:
- Around line 18-19: The exported routing namespace is exposing internal detail
helpers through the public ABI. Update the namespace declaration around
cuopt::routing in routing_structures.hpp so that detail stays hidden, either by
removing the export from the enclosing routing namespace or by placing detail
outside the exported namespace; use the cuopt::routing and
cuopt::routing::detail symbols to keep internal-only helpers out of the exported
surface.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 14cd8098-3d2d-49e3-be87-1acfca2543f1

📥 Commits

Reviewing files that changed from the base of the PR and between 7ba168e and bb9a313.

📒 Files selected for processing (70)
  • ci/check_symbols.sh
  • conda/recipes/libcuopt/recipe.yaml
  • cpp/CMakeLists.txt
  • cpp/include/cuopt/error.hpp
  • cpp/include/cuopt/export.hpp
  • cpp/include/cuopt/grpc/cython_grpc_client.hpp
  • cpp/include/cuopt/grpc/grpc_client_env.hpp
  • cpp/include/cuopt/mathematical_optimization/backend_selection.hpp
  • cpp/include/cuopt/mathematical_optimization/cpu_optimization_problem.hpp
  • cpp/include/cuopt/mathematical_optimization/cpu_optimization_problem_solution.hpp
  • cpp/include/cuopt/mathematical_optimization/cpu_pdlp_warm_start_data.hpp
  • cpp/include/cuopt/mathematical_optimization/cuopt_c.h
  • cpp/include/cuopt/mathematical_optimization/io/data_model_view.hpp
  • cpp/include/cuopt/mathematical_optimization/io/mps_data_model.hpp
  • cpp/include/cuopt/mathematical_optimization/io/mps_writer.hpp
  • cpp/include/cuopt/mathematical_optimization/io/parser.hpp
  • cpp/include/cuopt/mathematical_optimization/io/utilities/cython_parser.hpp
  • cpp/include/cuopt/mathematical_optimization/io/writer.hpp
  • cpp/include/cuopt/mathematical_optimization/mip/solver_settings.hpp
  • cpp/include/cuopt/mathematical_optimization/mip/solver_solution.hpp
  • cpp/include/cuopt/mathematical_optimization/optimization_problem.hpp
  • cpp/include/cuopt/mathematical_optimization/optimization_problem_solution.hpp
  • cpp/include/cuopt/mathematical_optimization/pdlp/pdlp_warm_start_data.hpp
  • cpp/include/cuopt/mathematical_optimization/pdlp/solver_settings.hpp
  • cpp/include/cuopt/mathematical_optimization/pdlp/solver_solution.hpp
  • cpp/include/cuopt/mathematical_optimization/solve.hpp
  • cpp/include/cuopt/mathematical_optimization/solve_remote.hpp
  • cpp/include/cuopt/mathematical_optimization/solver_settings.hpp
  • cpp/include/cuopt/mathematical_optimization/utilities/cython_solve.hpp
  • cpp/include/cuopt/mathematical_optimization/utilities/cython_types.hpp
  • cpp/include/cuopt/routing/assignment.hpp
  • cpp/include/cuopt/routing/cython/cython.hpp
  • cpp/include/cuopt/routing/data_model_view.hpp
  • cpp/include/cuopt/routing/routing_structures.hpp
  • cpp/include/cuopt/routing/solve.hpp
  • cpp/include/cuopt/routing/solver_settings.hpp
  • cpp/src/grpc/client/solve_remote.cpp
  • cpp/src/grpc/grpc_problem_mapper.cpp
  • cpp/src/grpc/grpc_settings_mapper.cpp
  • cpp/src/grpc/grpc_solution_mapper.cpp
  • cpp/src/io/data_model_view.cpp
  • cpp/src/io/lp_parser.cpp
  • cpp/src/io/mps_data_model.cpp
  • cpp/src/io/mps_writer.cpp
  • cpp/src/io/parser.cpp
  • cpp/src/io/writer.cpp
  • cpp/src/math_optimization/solution_reader.hpp
  • cpp/src/math_optimization/solver_settings.cu
  • cpp/src/mip_heuristics/solve.cu
  • cpp/src/mip_heuristics/solver_settings.cu
  • cpp/src/mip_heuristics/solver_solution.cu
  • cpp/src/pdlp/cpu_optimization_problem.cpp
  • cpp/src/pdlp/cpu_pdlp_warm_start_data.cu
  • cpp/src/pdlp/optimization_problem.cu
  • cpp/src/pdlp/pdlp_warm_start_data.cu
  • cpp/src/pdlp/solution_conversion.cu
  • cpp/src/pdlp/solve.cu
  • cpp/src/pdlp/solver_settings.cu
  • cpp/src/pdlp/solver_solution.cu
  • cpp/src/routing/assignment.cu
  • cpp/src/routing/data_model_view.cu
  • cpp/src/routing/distance_engine/waypoint_matrix.cpp
  • cpp/src/routing/solve.cu
  • cpp/src/routing/solver_settings.cu
  • cpp/src/routing/utilities/cython.cu
  • cpp/src/utilities/logger.hpp
  • cpp/tests/CMakeLists.txt
  • cpp/tests/examples/routing/CMakeLists.txt
  • cpp/tests/linear_programming/CMakeLists.txt
  • cpp/tests/linear_programming/grpc/CMakeLists.txt

Comment thread ci/check_symbols.sh
Comment thread conda/recipes/libcuopt/recipe.yaml Outdated
Comment thread cpp/CMakeLists.txt Outdated
Comment thread cpp/include/cuopt/grpc/grpc_client_env.hpp
@arhag23 arhag23 force-pushed the fix-symbol-visibility-2 branch from bb9a313 to 96f1647 Compare July 7, 2026 22:21
@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

CI Test Summary

✅ All 31 test job(s) passed.

@arhag23 arhag23 force-pushed the fix-symbol-visibility-2 branch from 96f1647 to cdfa680 Compare July 7, 2026 22:29
arhag23 added 5 commits July 7, 2026 16:31
Signed-off-by: Arha Gatram <agatram@nvidia.com>
…static archive

Signed-off-by: Arha Gatram <agatram@nvidia.com>
Signed-off-by: Arha Gatram <agatram@nvidia.com>
Signed-off-by: Arha Gatram <agatram@nvidia.com>

@aliceb-nv aliceb-nv left a comment

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.

Approving engine side

Comment thread ci/check_symbols.sh Outdated
Comment thread ci/check_symbols.sh
Comment thread cpp/src/pdlp/solve.cu
Comment on lines 2334 to 2359
template optimization_problem_solution_t<int, F_TYPE> solve_lp_with_method( \
mip::problem_t<int, F_TYPE>& problem, \
pdlp_solver_settings_t<int, F_TYPE> const& settings, \
const timer_t& timer, \
bool is_batch_mode); \
\
template optimization_problem_solution_t<int, F_TYPE> batch_pdlp_solve( \
raft::handle_t const* handle_ptr, \
const cuopt::mathematical_optimization::io::mps_data_model_t<int, F_TYPE>& mps_data_model, \
const std::vector<int>& fractional, \
const std::vector<F_TYPE>& root_soln_x, \
pdlp_solver_settings_t<int, F_TYPE> const& settings); \
\
template optimization_problem_solution_t<int, F_TYPE> run_batch_pdlp( \
optimization_problem_t<int, F_TYPE>& problem, \
pdlp_solver_settings_t<int, F_TYPE> const& settings); \
\
template size_t compute_optimal_batch_size(const optimization_problem_t<int, F_TYPE>& problem, \
bool per_climber_objectives, \
bool per_climber_constraint_bounds, \
bool collect_solutions); \
\
template optimization_problem_t<int, F_TYPE> mps_data_model_to_optimization_problem( \
raft::handle_t const* handle_ptr, \
const cuopt::mathematical_optimization::io::mps_data_model_t<int, F_TYPE>& data_model); \
template void set_pdlp_solver_mode(pdlp_solver_settings_t<int, F_TYPE>& settings);

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.

We should probably export all of these as well. @Kh4ster to check

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.

I checked these against the public include file, batch_pdlp_solve and mps_data_model_to_optimization_problem are present in <cuopt/mathematical_optimization/solve.hpp> so I will export them also. The rest aren't in any public header file.

Comment thread cpp/CMakeLists.txt
"CUOPT_LOG_ACTIVE_LEVEL=RAPIDS_LOGGER_LOG_LEVEL_${LIBCUOPT_LOGGING_LEVEL}"
CUSPARSE_ENABLE_EXPERIMENTAL_API
)

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.

@ramakrishnap-nv should we add a target_link_options(cuopt PRIVATE "LINKER:--exclude-libs,ALL")? Otherwise PSLP symbols are embedded with default visibility afaik

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Agree

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.

I went with this, but is there any reason for using ALL rather than explicitly specifying PSLP (and if any other PRIVATE static libraries)?

target_link_libraries(GRPC_CLIENT_TEST
PRIVATE
cuopt
cuopt_static

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Any reason to change this to static?

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.

Yes, nearly all tests now link against the static library since almost all directly use internal functions that are hidden when linking against the shared library.

Comment thread cpp/CMakeLists.txt
"CUOPT_LOG_ACTIVE_LEVEL=RAPIDS_LOGGER_LOG_LEVEL_${LIBCUOPT_LOGGING_LEVEL}"
CUSPARSE_ENABLE_EXPERIMENTAL_API
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Agree

@arhag23

arhag23 commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

@ramakrishnap-nv We now build a static version of cuopt to link the tests against since they directly reference internal symbols not in the public header API. This grealy increases the size of the test binaries (~100 MB -> ~10 GB) since this embeds the kernel device code in the tests. Is this acceptable or do we want to look at alternatives? We can try exporting every internal symbol used for the tests, but this may lead to too much of the internals being visible.

@ramakrishnap-nv

Copy link
Copy Markdown
Collaborator

@ramakrishnap-nv We now build a static version of cuopt to link the tests against since they directly reference internal symbols not in the public header API. This grealy increases the size of the test binaries (~100 MB -> ~10 GB) since this embeds the kernel device code in the tests. Is this acceptable or do we want to look at alternatives? We can try exporting every internal symbol used for the tests, but this may lead to too much of the internals being visible.

Yeah, that was my main concern that the size of the tests would increase significantly. Are we doing same across all other RAPIDS projects? And these are normally uploaded to nightly registries, so that is another concern.

@arhag23

arhag23 commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Are we doing same across all other RAPIDS projects?

AFAIK other RAPIDS projects didn't need such a change for symbol visibility controls.

@ramakrishnap-nv

Copy link
Copy Markdown
Collaborator

Are we doing same across all other RAPIDS projects?

AFAIK other RAPIDS projects didn't need such a change for symbol visibility controls.

Hmm, in the issue @bdice mentioned that this has been done for cudf, cuml and others, so what is the extent. If possible, I would like to avoid static linking with test.

@arhag23

arhag23 commented Jul 10, 2026

Copy link
Copy Markdown
Contributor Author

Are we doing same across all other RAPIDS projects?

AFAIK other RAPIDS projects didn't need such a change for symbol visibility controls.

Hmm, in the issue @bdice mentioned that this has been done for cudf, cuml and others, so what is the extent. If possible, I would like to avoid static linking with test.

I think those libraries didn't have tests against the library internals so they never ran into this issue. To avoid static linking with the tests, we have to either export all the internals tested against or disable visibility controls when building for the tests. Unfortunately none of these options seem like the "correct" thing to do.

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.

Hide internal C++ symbols exported from libcuopt

3 participants