Skip to content
Open
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
15 changes: 14 additions & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ REPODIR=$(cd "$(dirname "$0")"; pwd)
LIBCUOPT_BUILD_DIR=${LIBCUOPT_BUILD_DIR:=${REPODIR}/cpp/build}
LIBMPS_PARSER_BUILD_DIR=${LIBMPS_PARSER_BUILD_DIR:=${REPODIR}/cpp/libmps_parser/build}

VALIDARGS="clean libcuopt cuopt_grpc_server libmps_parser cuopt_mps_parser cuopt cuopt_server cuopt_sh_client docs deb -a -b -g -fsanitize -tsan -msan -v -l= --verbose-pdlp --build-lp-only --no-fetch-rapids --skip-c-python-adapters --skip-tests-build --skip-routing-build --skip-grpc-build --skip-fatbin-write --host-lineinfo [--cmake-args=\\\"<args>\\\"] [--cache-tool=<tool>] -n --allgpuarch --ci-only-arch --show_depr_warn -h --help"
VALIDARGS="clean codegen libcuopt cuopt_grpc_server libmps_parser cuopt_mps_parser cuopt cuopt_server cuopt_sh_client docs deb -a -b -g -fsanitize -tsan -msan -v -l= --verbose-pdlp --build-lp-only --no-fetch-rapids --skip-c-python-adapters --skip-tests-build --skip-routing-build --skip-grpc-build --skip-fatbin-write --host-lineinfo [--cmake-args=\\\"<args>\\\"] [--cache-tool=<tool>] -n --allgpuarch --ci-only-arch --show_depr_warn -h --help"
HELP="$0 [<target> ...] [<flag> ...]
where <target> is:
clean - remove all existing build artifacts and configuration (start over)
codegen - regenerate gRPC .inc files and proto from field_registry.yaml (requires pyyaml)
libcuopt - build the cuopt C++ code
cuopt_grpc_server - build only the gRPC server binary (configures + builds libcuopt as needed)
libmps_parser - build the libmps_parser C++ code
Expand Down Expand Up @@ -364,6 +365,18 @@ if buildAll || hasArg libmps_parser; then
fi
fi

################################################################################
# Regenerate gRPC codegen .inc files from the field registry (explicit target only)
if hasArg codegen; then
echo "Regenerating codegen .inc files from field_registry.yaml..."
python "${REPODIR}"/cpp/src/grpc/codegen/generate_conversions.py \
--registry "${REPODIR}"/cpp/src/grpc/codegen/field_registry.yaml \
--output-dir "${REPODIR}"/cpp/src/grpc/codegen/generated
cp "${REPODIR}"/cpp/src/grpc/codegen/generated/cuopt_remote_data.proto \
"${REPODIR}"/cpp/src/grpc/cuopt_remote_data.proto
echo "Done. Remember to commit the generated files."
Comment on lines +370 to +377
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clear orphaned generated files before regenerating.

This target writes into the existing cpp/src/grpc/codegen/generated tree but never removes files the generator no longer emits. When the registry drops an artifact, ./build.sh codegen leaves the stale file behind and ci/verify_grpc_codegen.sh will still fail on the orphan, so the documented regen flow does not fully converge.

Possible fix
 if hasArg codegen; then
     echo "Regenerating codegen .inc files from field_registry.yaml..."
+    if [ -d "${REPODIR}"/cpp/src/grpc/codegen/generated ]; then
+        find "${REPODIR}"/cpp/src/grpc/codegen/generated -mindepth 1 -maxdepth 1 -type f -delete
+    fi
     python "${REPODIR}"/cpp/src/grpc/codegen/generate_conversions.py \
         --registry "${REPODIR}"/cpp/src/grpc/codegen/field_registry.yaml \
         --output-dir "${REPODIR}"/cpp/src/grpc/codegen/generated
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if hasArg codegen; then
echo "Regenerating codegen .inc files from field_registry.yaml..."
python "${REPODIR}"/cpp/src/grpc/codegen/generate_conversions.py \
--registry "${REPODIR}"/cpp/src/grpc/codegen/field_registry.yaml \
--output-dir "${REPODIR}"/cpp/src/grpc/codegen/generated
cp "${REPODIR}"/cpp/src/grpc/codegen/generated/cuopt_remote_data.proto \
"${REPODIR}"/cpp/src/grpc/cuopt_remote_data.proto
echo "Done. Remember to commit the generated files."
if hasArg codegen; then
echo "Regenerating codegen .inc files from field_registry.yaml..."
if [ -d "${REPODIR}"/cpp/src/grpc/codegen/generated ]; then
find "${REPODIR}"/cpp/src/grpc/codegen/generated -mindepth 1 -maxdepth 1 -type f -delete
fi
python "${REPODIR}"/cpp/src/grpc/codegen/generate_conversions.py \
--registry "${REPODIR}"/cpp/src/grpc/codegen/field_registry.yaml \
--output-dir "${REPODIR}"/cpp/src/grpc/codegen/generated
cp "${REPODIR}"/cpp/src/grpc/codegen/generated/cuopt_remote_data.proto \
"${REPODIR}"/cpp/src/grpc/cuopt_remote_data.proto
echo "Done. Remember to commit the generated files."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@build.sh` around lines 370 - 377, The codegen step in build.sh leaves stale
files in the generated directory; before running generate_conversions.py delete
or clean the contents of cpp/src/grpc/codegen/generated (safely check existence
and remove files/dirs inside, preserving the directory itself if needed) so the
generator receives an empty output tree; then run generate_conversions.py and
copy the resulting cuopt_remote_data.proto as before. Locate the codegen block
in build.sh (the hasArg codegen branch) and insert a cleanup step that removes
all files/subdirectories under the generated folder prior to invoking the Python
generator.

fi

################################################################################
# Configure and build libcuopt (and optionally just the gRPC server)
if buildAll || hasArg libcuopt || hasArg cuopt_grpc_server; then
Expand Down
3 changes: 3 additions & 0 deletions ci/test_cpp.sh
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ mkdir -p "${RAPIDS_TESTS_DIR}"

rapids-print-env

rapids-logger "Verify gRPC codegen output matches committed files"
./ci/verify_grpc_codegen.sh

rapids-logger "Check GPU usage"
nvidia-smi

Expand Down
66 changes: 66 additions & 0 deletions ci/verify_grpc_codegen.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
#!/bin/bash
# SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
#
# Verify that committed codegen output matches what generate_conversions.py produces.
# Fails if a developer edited field_registry.yaml without re-running ./build.sh codegen.

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
CODEGEN_DIR="${REPO_DIR}/cpp/src/grpc/codegen"
GENERATED_DIR="${CODEGEN_DIR}/generated"
PROTO_DEST="${REPO_DIR}/cpp/src/grpc/cuopt_remote_data.proto"

TMPDIR=$(mktemp -d)
trap 'rm -rf ${TMPDIR}' EXIT

echo "Running code generator into temp directory..."
python "${CODEGEN_DIR}/generate_conversions.py" \
--registry "${CODEGEN_DIR}/field_registry.yaml" \
--output-dir "${TMPDIR}"

echo "Comparing generated output with committed files..."

FAILED=0

for f in "${TMPDIR}"/*; do
fname=$(basename "$f")
committed="${GENERATED_DIR}/${fname}"
if [ ! -f "${committed}" ]; then
echo "MISSING: ${committed} (new generated file not committed)"
FAILED=1
continue
fi
if ! diff -q "$f" "${committed}" > /dev/null 2>&1; then
echo "MISMATCH: cpp/src/grpc/codegen/generated/${fname}"
diff -u "${committed}" "$f" | head -30
FAILED=1
fi
done

for committed in "${GENERATED_DIR}"/*; do
[ -f "${committed}" ] || continue
fname=$(basename "${committed}")
if [ ! -f "${TMPDIR}/${fname}" ]; then
echo "ORPHANED: cpp/src/grpc/codegen/generated/${fname} (no longer generated)"
FAILED=1
fi
done

if [ -f "${TMPDIR}/cuopt_remote_data.proto" ] && [ -f "${PROTO_DEST}" ]; then
if ! diff -q "${TMPDIR}/cuopt_remote_data.proto" "${PROTO_DEST}" > /dev/null 2>&1; then
echo "MISMATCH: cpp/src/grpc/cuopt_remote_data.proto (not copied from codegen/generated)"
FAILED=1
fi
fi

if [ ${FAILED} -ne 0 ]; then
echo ""
echo "ERROR: Committed generated files are out of sync with field_registry.yaml."
echo "Run './build.sh codegen' and commit the results."
exit 1
fi

echo "OK: All generated files match field_registry.yaml."
1 change: 1 addition & 0 deletions conda/environments/all_cuda-129_arch-aarch64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ dependencies:
- re2
- requests
- rmm==26.6.*,>=0.0.0a0
- ruamel.yaml>=0.18
- scikit-build-core>=0.11.0
- scipy>=1.14.1
- sphinx
Expand Down
1 change: 1 addition & 0 deletions conda/environments/all_cuda-129_arch-x86_64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ dependencies:
- re2
- requests
- rmm==26.6.*,>=0.0.0a0
- ruamel.yaml>=0.18
- scikit-build-core>=0.11.0
- scipy>=1.14.1
- sphinx
Expand Down
1 change: 1 addition & 0 deletions conda/environments/all_cuda-131_arch-aarch64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ dependencies:
- re2
- requests
- rmm==26.6.*,>=0.0.0a0
- ruamel.yaml>=0.18
- scikit-build-core>=0.11.0
- scipy>=1.14.1
- sphinx
Expand Down
1 change: 1 addition & 0 deletions conda/environments/all_cuda-131_arch-x86_64.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ dependencies:
- re2
- requests
- rmm==26.6.*,>=0.0.0a0
- ruamel.yaml>=0.18
- scikit-build-core>=0.11.0
- scipy>=1.14.1
- sphinx
Expand Down
39 changes: 32 additions & 7 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -339,24 +339,45 @@ if (NOT SKIP_GRPC_BUILD)
endif ()
endif ()

# Generate C++ code from cuopt_remote.proto (base message definitions)
set(PROTO_FILE "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/cuopt_remote.proto")
# Proto search paths: manual protos in src/grpc, generated data proto in src/grpc/codegen/generated
set(PROTO_PATH_MANUAL "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc")
set(PROTO_PATH_GEN "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/codegen/generated")

# Generate C++ code from cuopt_remote_data.proto (auto-generated data definitions)
set(DATA_PROTO_FILE "${PROTO_PATH_GEN}/cuopt_remote_data.proto")
set(DATA_PROTO_SRCS "${CMAKE_CURRENT_BINARY_DIR}/cuopt_remote_data.pb.cc")
set(DATA_PROTO_HDRS "${CMAKE_CURRENT_BINARY_DIR}/cuopt_remote_data.pb.h")

add_custom_command(
OUTPUT "${DATA_PROTO_SRCS}" "${DATA_PROTO_HDRS}"
COMMAND ${_PROTOBUF_PROTOC}
ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR}
--proto_path ${PROTO_PATH_GEN}
${DATA_PROTO_FILE}
DEPENDS ${DATA_PROTO_FILE}
COMMENT "Generating C++ code from cuopt_remote_data.proto"
VERBATIM
)

# Generate C++ code from cuopt_remote.proto (control/protocol messages, imports data proto)
set(PROTO_FILE "${PROTO_PATH_MANUAL}/cuopt_remote.proto")
set(PROTO_SRCS "${CMAKE_CURRENT_BINARY_DIR}/cuopt_remote.pb.cc")
set(PROTO_HDRS "${CMAKE_CURRENT_BINARY_DIR}/cuopt_remote.pb.h")

add_custom_command(
OUTPUT "${PROTO_SRCS}" "${PROTO_HDRS}"
COMMAND ${_PROTOBUF_PROTOC}
ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR}
--proto_path ${CMAKE_CURRENT_SOURCE_DIR}/src/grpc
--proto_path ${PROTO_PATH_MANUAL}
--proto_path ${PROTO_PATH_GEN}
${PROTO_FILE}
DEPENDS ${PROTO_FILE}
DEPENDS ${PROTO_FILE} ${DATA_PROTO_FILE}
COMMENT "Generating C++ code from cuopt_remote.proto"
VERBATIM
)

# Generate gRPC service code from cuopt_remote_service.proto
set(GRPC_PROTO_FILE "${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/cuopt_remote_service.proto")
set(GRPC_PROTO_FILE "${PROTO_PATH_MANUAL}/cuopt_remote_service.proto")
set(GRPC_PROTO_SRCS "${CMAKE_CURRENT_BINARY_DIR}/cuopt_remote_service.pb.cc")
set(GRPC_PROTO_HDRS "${CMAKE_CURRENT_BINARY_DIR}/cuopt_remote_service.pb.h")
set(GRPC_SERVICE_SRCS "${CMAKE_CURRENT_BINARY_DIR}/cuopt_remote_service.grpc.pb.cc")
Expand All @@ -368,9 +389,10 @@ if (NOT SKIP_GRPC_BUILD)
ARGS --cpp_out ${CMAKE_CURRENT_BINARY_DIR}
--grpc_out ${CMAKE_CURRENT_BINARY_DIR}
--plugin=protoc-gen-grpc=${_GRPC_CPP_PLUGIN_EXECUTABLE}
--proto_path ${CMAKE_CURRENT_SOURCE_DIR}/src/grpc
--proto_path ${PROTO_PATH_MANUAL}
--proto_path ${PROTO_PATH_GEN}
${GRPC_PROTO_FILE}
DEPENDS ${GRPC_PROTO_FILE} ${PROTO_FILE} ${PROTO_SRCS} ${PROTO_HDRS}
DEPENDS ${GRPC_PROTO_FILE} ${PROTO_FILE} ${DATA_PROTO_FILE}
COMMENT "Generating gRPC C++ code from cuopt_remote_service.proto"
VERBATIM
)
Expand Down Expand Up @@ -402,6 +424,7 @@ endif ()
if (NOT SKIP_GRPC_BUILD)
# Add gRPC mapper files and generated protobuf sources
set(GRPC_INFRA_FILES
${DATA_PROTO_SRCS}
${PROTO_SRCS}
${GRPC_PROTO_SRCS}
${GRPC_SERVICE_SRCS}
Expand Down Expand Up @@ -480,6 +503,7 @@ target_include_directories(cuopt
"${CMAKE_CURRENT_SOURCE_DIR}/src"
"${CMAKE_CURRENT_SOURCE_DIR}/src/grpc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/client"
"${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/codegen/generated"
"${CMAKE_CURRENT_BINARY_DIR}"
"${CUDSS_INCLUDE}"
PUBLIC
Expand Down Expand Up @@ -813,6 +837,7 @@ if (NOT SKIP_GRPC_BUILD)
"${CMAKE_CURRENT_SOURCE_DIR}/src"
"${CMAKE_CURRENT_SOURCE_DIR}/src/grpc"
"${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/server"
"${CMAKE_CURRENT_SOURCE_DIR}/src/grpc/codegen/generated"
"${CMAKE_CURRENT_SOURCE_DIR}/include"
"${CMAKE_CURRENT_SOURCE_DIR}/libmps_parser/include"
"${CMAKE_CURRENT_BINARY_DIR}"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,18 @@ class cpu_optimization_problem_t : public optimization_problem_interface_t<i_t,
const std::vector<i_t>& get_quadratic_objective_offsets() const override;
const std::vector<i_t>& get_quadratic_objective_indices() const override;
const std::vector<f_t>& get_quadratic_objective_values() const override;
const std::vector<i_t>& get_quadratic_objective_offsets_host() const
{
return get_quadratic_objective_offsets();
}
const std::vector<i_t>& get_quadratic_objective_indices_host() const
{
return get_quadratic_objective_indices();
}
const std::vector<f_t>& get_quadratic_objective_values_host() const
{
return get_quadratic_objective_values();
}
bool has_quadratic_objective() const override;

void set_quadratic_constraints(std::vector<quadratic_constraint_t> constraints) override;
Expand Down
Loading
Loading