Skip to content
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

[FIXED] C++ compiler errors #832

Merged
merged 6 commits into from
Jan 15, 2025
Merged
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
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -307,4 +307,5 @@ if(NATS_BUILD_STREAMING)
endif()
add_subdirectory(test)
add_subdirectory(test/dylib)
add_subdirectory(test/check_cpp)
#----------------------------
8 changes: 8 additions & 0 deletions buildOnTravis.sh
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,14 @@ if [ $res -ne 0 ]; then
exit $res
fi

echo "Test C++ compiler compatibility"
# There is mo need to run check, just make sure it's compiled
bin/check_cpp
res=$?
if [ $res -ne 0 ]; then
exit $res
fi

export NATS_TEST_TRAVIS=yes
echo "Using NATS server version: $NATS_TEST_SERVER_VERSION"
ctest -L 'test' --timeout 60 --output-on-failure $4
Expand Down
239 changes: 127 additions & 112 deletions src/nats.h
Original file line number Diff line number Diff line change
Expand Up @@ -1239,125 +1239,140 @@ typedef void (*jsFetchCompleteHandler)(natsConnection *nc, natsSubscription *sub
*/
typedef bool (*jsFetchNextHandler)(int *messages, int64_t *maxBytes, natsSubscription *sub, void *closure);

/**
* Async pull subscriber options.
*
* Part of #jsOptions.
*/
typedef struct jsOptionsPullSubscribeAsync
Copy link
Member

Choose a reason for hiding this comment

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

I have no issue making the jsOptionsPullSubscribeAsync a typedef structure, instead of being "embedded" in jsOpts, but if the issue is only because a user tries to include natsp.h, then I would not consider changing anything.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

yes I think that is the case. do you think moving to typedefs is still worth while for future proofing?

Copy link
Member

Choose a reason for hiding this comment

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

At this point no (seeing all the build failures).

At the very least, what you could do is update the PR by removing the cpp file and changes to examples' make file. Keep the changes in nats.h. Assuming there is no build issue, this PR should still be updated because then we would need to require a new version here because the header is changed.

If there is still build failures, have a new branch that is just pointing to main and push to see if CI still has build issues. If not, then let's close this PR. If there is still build issues, they may be temporary and I would feel better wait for those issues to be resolved with the main branch before trying to include this modified PR.

Choose a reason for hiding this comment

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

We got into the current state because we include natsp.h because we wrote our own watcher around the kvWatcher. We did that so we could invoke a callback on the data. This is all before I got here. I will be looking into the NATS API around this private data structure as soon as I post this, so I haven't yet looked at the API as it exists. Is there an API that would invoke a callback per message that we either missed, or you added after this implementation?

Copy link
Collaborator Author

@mtmk mtmk Jan 14, 2025

Choose a reason for hiding this comment

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

ok removed the cpp and reverted cmake. build seems fine now apart from couple of flappers presumably.

edit: should I move rest of the nested definitions for consistency?

Copy link
Member

Choose a reason for hiding this comment

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

@mtmk Then we should still update the main make file as I mentioned earlier. That being said, it could be done as part of the next release. Also, we need to make sure that this PR does not end-up in the patch release. @levb can confirm.

Also, @PhilBarila does that mean that you are using other internals? That would not be too good, but regardless, if the change in this PR is enough to "fix" your issue, then fine.

In that case, @mtmk, the check.cpp may instead be in the test directory. It could be a subdirectory, similar to this. It would also need to be added to the tests to run like we do it here.

If this is confusing, I could do that as a separate PR later. Let me know.

Choose a reason for hiding this comment

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

The kvWatcher is the only thing we used from the natsp.h. If you have an alternative to writing our own jet-stream watcher, we'll take a very serious look at it ...

Copy link
Member

Choose a reason for hiding this comment

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

Is there an API that would invoke a callback per message that we either missed, or you added after this implementation?

@PhilBarila, you can create a watcher, but they are sync by nature, so you need to call their "next" API. I am not sure what you did exactly using the internal structure, so it is difficult for me to say if there is equivalent or not (if it is just to be a callback instead of a sync call, it sounds like a thread calling kvWatcher_Next() and invoking your callback with the result may be enough)

Choose a reason for hiding this comment

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

And pull the data out of it with kvEntry_Value ... I'll have to do more digging, but that might work. I am only just wading in, so there's lots more to learn before we have a clean path forward to stop depending on your private data ... But we'll get it done as soon as is practical with all the other competing priorities ...

{
int64_t Timeout; ///< Auto-unsubsribe after this many milliseconds.
int MaxMessages; ///< Auto-unsubscribed after receiving this many messages.
int64_t MaxBytes; ///< Auto-unsubscribe after receiving this many bytes.

/// \brief If NoWait is set, the subscription will receive the
/// messages already stored on the server subject to the limits,
/// but will not wait for more messages.
///
/// \note that if Timeout is set we would still wait for first
/// message to become available, even if there are currently any
/// on the server
bool NoWait;

/// \brief Fetch complete handler that receives the exit status
/// code, the subscription's Complete handler is also invoked,
/// but does not have the status code.
jsFetchCompleteHandler CompleteHandler;
void *CompleteHandlerClosure;

/// \brief Have server sends heartbeats at this interval (in
/// milliseconds) to help detect communication failures.
int64_t Heartbeat;

/// @brief When using the automatic Fetch flow control (default
/// NextHandler), this is the number of messages to ask for in a
/// single request.
int FetchSize;

/// @brief When using the automatic Fetch flow control (default
/// NextHandler), initiate the next fetch request (this many
/// messages) prior to the fulfillment of the current request.
///
/// @note KeepAhead can not be used in conjunction with MaxBytes
/// or NoWait.
int KeepAhead;

/// @brief If set, switches to manual fetch flow control.
///
/// If provided, this function gets called before each message
/// is deliverered to msgCB, and overrides the default algorithm
/// for sending Next fetch requests.
jsFetchNextHandler NextHandler;
void *NextHandlerClosure;

} jsOptionsPullSubscribeAsync;

/**
* Async pull options.
*
* Part of #jsOptions.
*/
typedef struct jsOptionsPublishAsync
{
int64_t MaxPending; ///< Maximum outstanding asynchronous publishes that can be inflight at one time.

// If jsPubAckHandler is specified, the callback will be invoked
// for every asynchronous published message, either as a positive
// result, or with the error encountered when publishing that
// message. If this callback is specified, ErrHandler (see below)
// will be ignored.
jsPubAckHandler AckHandler; ///< Callback invoked for each asynchronous published message.
void *AckHandlerClosure; ///< Closure (or user data) passed to #jsPubAckHandler callback.

// This callback is invoked for messages published asynchronously
// when an error is returned by the server or if the library has
// timed-out waiting for an acknowledgment back from the server
// (if publish uses the jsPubOptions.MaxWait).
jsPubAckErrHandler ErrHandler; ///< Callback invoked when error encountered publishing a given message.
void *ErrHandlerClosure; ///< Closure (or user data) passed to #jsPubAckErrHandler callback.

int64_t StallWait; ///< Amount of time (in milliseconds) to wait in a PublishAsync call when there is MaxPending inflight messages, default is 200 ms.

} jsOptionsPublishAsync;

/**
* Advanced stream purge options
*
* * `Subject` will filter the purge request to only messages that match the subject, which can have wildcards.<br>
* * `Sequence` will purge up to but not including this sequence and can be combined with subject filtering.<br>
* * `Keep` will specify how many messages to keep and can be combined with subject filtering.<br>
*
* \note `Sequence` and `Keep` are mutually exclusive, so both can not be set at the same time.
*/
typedef struct jsOptionsStreamPurge
{
const char *Subject; ///< This is the subject to match against messages for the purge command.
uint64_t Sequence; ///< Purge up to but not including sequence.
uint64_t Keep; ///< Number of messages to keep.

} jsOptionsStreamPurge;

/**
* Advance stream information retrieval options
*/
typedef struct jsOptionsStreamInfo
{
bool DeletedDetails; ///< Get the list of deleted message sequences.
const char *SubjectsFilter; ///< Get the list of subjects in this stream.

} jsOptionsStreamInfo;

/**
* Advanced stream options
*
* * `Purge` for advanced purge options.
* * `Info` for advanced information retrieval options.
*/
typedef struct jsOptionsStream
{
jsOptionsStreamPurge Purge; ///< Optional stream purge options.
jsOptionsStreamInfo Info; ///< Optional stream information retrieval options.

} jsOptionsStream;

/**
* JetStream context options.
*
* Initialize the object with #jsOptions_Init.
*/
typedef struct jsOptions
{
const char *Prefix; ///< JetStream prefix, default is "$JS.API"
const char *Domain; ///< Domain changes the domain part of JetSteam API prefix.
int64_t Wait; ///< Amount of time (in milliseconds) to wait for various JetStream API requests, default is 5000 ms (5 seconds).

struct jsOptionsPublishAsync
{
int64_t MaxPending; ///< Maximum outstanding asynchronous publishes that can be inflight at one time.

// If jsPubAckHandler is specified, the callback will be invoked
// for every asynchronous published message, either as a positive
// result, or with the error encountered when publishing that
// message. If this callback is specified, ErrHandler (see below)
// will be ignored.
jsPubAckHandler AckHandler; ///< Callback invoked for each asynchronous published message.
void *AckHandlerClosure; ///< Closure (or user data) passed to #jsPubAckHandler callback.

// This callback is invoked for messages published asynchronously
// when an error is returned by the server or if the library has
// timed-out waiting for an acknowledgment back from the server
// (if publish uses the jsPubOptions.MaxWait).
jsPubAckErrHandler ErrHandler; ///< Callback invoked when error encountered publishing a given message.
void *ErrHandlerClosure; ///< Closure (or user data) passed to #jsPubAckErrHandler callback.

int64_t StallWait; ///< Amount of time (in milliseconds) to wait in a PublishAsync call when there is MaxPending inflight messages, default is 200 ms.

} PublishAsync; ///< extra options for #js_PublishAsync

struct jsOptionsPullSubscribeAsync
{
int64_t Timeout; ///< Auto-unsubsribe after this many milliseconds.
int MaxMessages; ///< Auto-unsubscribed after receiving this many messages.
int64_t MaxBytes; ///< Auto-unsubscribe after receiving this many bytes.

/// \brief If NoWait is set, the subscription will receive the
/// messages already stored on the server subject to the limits,
/// but will not wait for more messages.
///
/// \note that if Timeout is set we would still wait for first
/// message to become available, even if there are currently any
/// on the server
bool NoWait;

/// \brief Fetch complete handler that receives the exit status
/// code, the subscription's Complete handler is also invoked,
/// but does not have the status code.
jsFetchCompleteHandler CompleteHandler;
void *CompleteHandlerClosure;

/// \brief Have server sends heartbeats at this interval (in
/// milliseconds) to help detect communication failures.
int64_t Heartbeat;

/// @brief When using the automatic Fetch flow control (default
/// NextHandler), this is the number of messages to ask for in a
/// single request.
int FetchSize;

/// @brief When using the automatic Fetch flow control (default
/// NextHandler), initiate the next fetch request (this many
/// messages) prior to the fulfillment of the current request.
///
/// @note KeepAhead can not be used in conjunction with MaxBytes
/// or NoWait.
int KeepAhead;

/// @brief If set, switches to manual fetch flow control.
///
/// If provided, this function gets called before each message
/// is deliverered to msgCB, and overrides the default algorithm
/// for sending Next fetch requests.
jsFetchNextHandler NextHandler;
void *NextHandlerClosure;

} PullSubscribeAsync; ///< extra options for #js_PullSubscribeAsync


/**
* Advanced stream options
*
* * `Purge` for advanced purge options.
* * `Info` for advanced information retrieval options.
*/
struct jsOptionsStream
{
/**
* Advanced stream purge options
*
* * `Subject` will filter the purge request to only messages that match the subject, which can have wildcards.<br>
* * `Sequence` will purge up to but not including this sequence and can be combined with subject filtering.<br>
* * `Keep` will specify how many messages to keep and can be combined with subject filtering.<br>
*
* \note `Sequence` and `Keep` are mutually exclusive, so both can not be set at the same time.
*/
struct jsOptionsStreamPurge
{
const char *Subject; ///< This is the subject to match against messages for the purge command.
uint64_t Sequence; ///< Purge up to but not including sequence.
uint64_t Keep; ///< Number of messages to keep.

} Purge; ///< Optional stream purge options.

/**
* Advance stream information retrieval options
*/
struct jsOptionsStreamInfo
{
bool DeletedDetails; ///< Get the list of deleted message sequences.
const char *SubjectsFilter; ///< Get the list of subjects in this stream.

} Info; ///< Optional stream information retrieval options.

} Stream; ///< Optional stream options.
const char *Prefix; ///< JetStream prefix, default is "$JS.API"
const char *Domain; ///< Domain changes the domain part of JetSteam API prefix.
int64_t Wait; ///< Amount of time (in milliseconds) to wait for various JetStream API requests, default is 5000 ms (5 seconds).
jsOptionsPublishAsync PublishAsync; ///< extra options for #js_PublishAsync
jsOptionsPullSubscribeAsync PullSubscribeAsync; ///< extra options for #js_PullSubscribeAsync
jsOptionsStream Stream; ///< Optional stream options.

} jsOptions;

Expand Down
25 changes: 25 additions & 0 deletions test/check_cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
if(NOT BUILD_TESTING)
return()
endif()

Copy link
Member

Choose a reason for hiding this comment

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

There are failures on Travis for clang with sanitize. Not exactly sure why. So maybe try to build statically, so add this to this make file.

if(NOT NATS_BUILD_LIB_STATIC)
MESSAGE(FATAL_ERROR
"Building tests require static library, or run CMake with -DBUILD_TESTING=OFF")
return()
endif()

if(MSVC)
set_source_files_properties(test.c PROPERTIES COMPILE_FLAGS "/w")
endif()

# We need this to build the test program
include_directories(${PROJECT_SOURCE_DIR}/src)

if(NATS_BUILD_WITH_TLS)
include_directories(${OPENSSL_INCLUDE_DIR})
endif(NATS_BUILD_WITH_TLS)

# Build the test program
add_executable(check_cpp check_cpp.cpp)

target_link_libraries(check_cpp nats_static ${NATS_EXTRA_LIB})
29 changes: 29 additions & 0 deletions test/check_cpp/check_cpp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright 2017-2025 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <iostream>
#include <nats.h>

// Check C++ compiler compatibility of structs in
// natsp.h to avoid incomplete type errors such as C2079.
#include <natsp.h>

int main(int argc, char **argv)
{
// jsOptionsPullSubscribeAsync opts should be accessible
jsFetch fetch;
fetch.opts.Timeout = 1;

std::cout << "OK" << std::endl;
return 0;
}
Loading