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

Feature/c api #57

Open
wants to merge 12 commits into
base: develop
Choose a base branch
from
Open

Feature/c api #57

wants to merge 12 commits into from

Conversation

ChrisspyB
Copy link
Member

No description provided.

@codecov-commenter
Copy link

codecov-commenter commented Dec 11, 2024

Codecov Report

Attention: Patch coverage is 74.90909% with 69 lines in your changes missing coverage. Please review.

Project coverage is 61.11%. Comparing base (963c295) to head (bf9f488).

Files with missing lines Patch % Lines
src/metkit/api/metkit_c.cc 64.79% 69 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop      #57      +/-   ##
===========================================
+ Coverage    60.39%   61.11%   +0.71%     
===========================================
  Files          101      103       +2     
  Lines         6242     6517     +275     
  Branches       585      590       +5     
===========================================
+ Hits          3770     3983     +213     
- Misses        2472     2534      +62     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@ChrisspyB ChrisspyB requested a review from tbkr December 16, 2024 09:43
@ChrisspyB ChrisspyB marked this pull request as ready for review December 16, 2024 09:43
Copy link
Member Author

Choose a reason for hiding this comment

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

Todo: Ensure we cover all functionality currently in fdb_c so that we can replace it with this.

Copy link

Choose a reason for hiding this comment

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

Looks good so far. The functionality of the pyfdb is the following:

struct fdb_request_t;
typedef struct fdb_request_t fdb_request_t;
int fdb_new_request(fdb_request_t** req);
int fdb_request_add(fdb_request_t* req, const char* param, const char* values[], int numValues);
int fdb_expand_request(fdb_request_t* req);
int fdb_delete_request(fdb_request_t* req);

Those are all contained in the request section. Do we need anything on top @ChrisspyB?

Copy link

@tbkr tbkr left a comment

Choose a reason for hiding this comment

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

Like the changes. Code and Documentation was extraordinarily clean. I was a bit nitpicky. Bear with me in case some of my suggestions are not compatible with modern C; it has been a while since I programmed in C ;)

src/metkit/api/metkit_c.cc Outdated Show resolved Hide resolved
src/metkit/api/metkit_c.cc Outdated Show resolved Hide resolved
/// @comment: (maby)
/// Not sure if there is much value in having a param iterator. We could just return an array of
/// strings (char**) using metkit_marsrequest_params.
/// I think we should metkit_paramiterator_t.
Copy link

Choose a reason for hiding this comment

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

Here the comment is lacking some words. Do this need to be addressed before merging?

Copy link
Member Author

Choose a reason for hiding this comment

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

a todo left for me by me

src/metkit/api/metkit_c.cc Outdated Show resolved Hide resolved

} // extern "C"

static thread_local std::string g_current_error_string;
Copy link

Choose a reason for hiding this comment

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

This is read-only, isn't it? Make it const.

src/metkit/api/metkit_c.cc Outdated Show resolved Hide resolved
tests/test_c_api.cc Outdated Show resolved Hide resolved
tests/test_c_api.cc Show resolved Hide resolved
src/metkit/api/metkit_c.h Show resolved Hide resolved
Copy link

Choose a reason for hiding this comment

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

Looks good so far. The functionality of the pyfdb is the following:

struct fdb_request_t;
typedef struct fdb_request_t fdb_request_t;
int fdb_new_request(fdb_request_t** req);
int fdb_request_add(fdb_request_t* req, const char* param, const char* values[], int numValues);
int fdb_expand_request(fdb_request_t* req);
int fdb_delete_request(fdb_request_t* req);

Those are all contained in the request section. Do we need anything on top @ChrisspyB?

src/metkit/api/metkit_c.h Outdated Show resolved Hide resolved
src/metkit/api/metkit_c.h Outdated Show resolved Hide resolved
src/metkit/api/metkit_c.h Outdated Show resolved Hide resolved
src/metkit/api/metkit_c.h Show resolved Hide resolved
src/metkit/api/metkit_c.h Show resolved Hide resolved
Copy link

@Ozaq Ozaq left a comment

Choose a reason for hiding this comment

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

You need an extra test where you use the API and compile the test with a C compiler

typedef enum metkit_error_values_t
{
METKIT_SUCCESS = 0, /* Operation succeded. */
METKIT_ITERATION_COMPLETE = 1, /* All elements have been returned */
Copy link

Choose a reason for hiding this comment

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

This is not an error and should be handled differently. Right now this mixes error and result states. I would advocate for a strict separation.

src/metkit/api/metkit_c.h Outdated Show resolved Hide resolved
src/metkit/api/metkit_c.h Show resolved Hide resolved
src/metkit/api/metkit_c.h Show resolved Hide resolved
*
* @note This is ONLY required when Main() is NOT initialised, such as loading
* the MetKit as shared library in Python.
* @return int Error code
Copy link

Choose a reason for hiding this comment

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

This should document the possible error codes returned from this function and under which circumstances the errors are to be expected.

The underlying issue here is that every possible error that can happen when using this API is corralled into metkit_error_values_t. When using such an API you will greatly thank the doc writer for stating the possible error cases, (think man pages for example) because this allows me to simplify error handling. And treat every unexpected EC as fatal error.

If the user is not given any information about the possible errors, he will always be wondering "Could this return a METKIT_ITERATION_COMPLETE?"

* @param it RequestIterator instance
* @return int Error code
*/
int metkit_requestiterator_next(metkit_requestiterator_t* it);
Copy link

Choose a reason for hiding this comment

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

I think this would make for a nicer API if we could use it like this:

while((res = metkit_paramiterator_next(it))) {
   //...
}

Ofc this would only work if the iteration cannot create errors. But return a nullptr on end of iteration makes for a more natural api imo.

src/metkit/api/metkit_c.h Outdated Show resolved Hide resolved
src/metkit/api/metkit_c.h Show resolved Hide resolved
tests/test_c_api.cc Outdated Show resolved Hide resolved
tests/test_c_api.cc Outdated Show resolved Hide resolved
src/metkit/api/metkit_c.cc Outdated Show resolved Hide resolved
/// Not sure if there is much value in having a param iterator. We could just return an array of
/// strings (char**) using metkit_marsrequest_params.
/// I think we should metkit_paramiterator_t.
struct metkit_paramiterator_t {
Copy link

Choose a reason for hiding this comment

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

Lifetimes of returned values in this iterator differ from the metkit_requestiterator_t iterator. For itself the lifetime is ok (if documented) but a subtle difference in lifetime handling with both types imply symmetrical behavior is a nasty trap. metkit_requestiterator_t result lifetimes exceed the iterator due to the move out of the iterator, while the char* from this iterator dangle as soon as the iterator is freed.

src/metkit/api/metkit_c.cc Outdated Show resolved Hide resolved
src/metkit/api/metkit_c.cc Outdated Show resolved Hide resolved
src/metkit/api/metkit_c.cc Outdated Show resolved Hide resolved
src/metkit/api/metkit_c.cc Show resolved Hide resolved
Comment on lines +131 to +139
int metkit_version(const char** version) {
*version = metkit_version_str();
return METKIT_SUCCESS;
}

int metkit_vcs_version(const char** sha1) {
*sha1 = metkit_git_sha1();
return METKIT_SUCCESS;
}
Copy link

Choose a reason for hiding this comment

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

So since its always METKIT_SUCCESS this should just return the const char*

src/metkit/api/metkit_c.cc Outdated Show resolved Hide resolved
src/metkit/api/metkit_c.cc Outdated Show resolved Hide resolved
src/metkit/api/metkit_c.cc Outdated Show resolved Hide resolved
src/metkit/api/metkit_c.cc Outdated Show resolved Hide resolved
@ChrisspyB
Copy link
Member Author

ChrisspyB commented Dec 20, 2024

You need an extra test where you use the API and compile the test with a C compiler

Maybe we should rewrite test_metkit_c.cc in C? For the time being I'll add a simple test that at least uses a C compiler

@ChrisspyB
Copy link
Member Author

Re: error handling, if we're going to do similar across the stack, it might make sense to centralise this somewhere (eckit). All of the caught exceptions are in fact eckit::exceptions

Comment on lines +85 to +93
# Compile C test
ecbuild_add_test( TARGET metkit_test_c_compiled
SOURCES test_c_api.c
INCLUDES "${ECKIT_INCLUDE_DIRS}"
LIBS metkit
NO_AS_NEEDED
ENVIRONMENT "${metkit_env}"
LINKER_LANGUAGE C)

Copy link

@Ozaq Ozaq Jan 8, 2025

Choose a reason for hiding this comment

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

It is not required to set LINKER_LANGUAGE C as this will be detected based on the file extension. If you still want to be explicit its probably better to set the language for the source file to 'C' as we want the source file to pass trough the C-Compilation, i.e. set_source_files_properties(test_c_api.c PROPERTIES LANGUAGE C)

You should also probably also add C to the project languages. Right now C is always enabled due to how we pull in ecbuild and hence it works but it is surprising to see that we invoke the C-Compiler although the make project explicitly only requests C++.
I.e. the top-level project declaration should become project( metkit LANGUAGES CXX C)

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.

6 participants