C++ Gurus - Is C++ a good choice for public API(s)??? Are there cleanways to solve known problems th

A

arijit79

Hi

I needed to build up a public API for an application at hand.

The data I am modelling maps very well to object oriented design, so I
am little inclined towards a C++ public API (i.e. my deliverables
would be a <xyz>.hpp file which will have a bunch of pure virtual
functions forming the interface and a lib<xyz>.so which will basically
contain the implementation for those interfaces).

But, I can think of 2 problems there:
1) How do I guarantee that my shared library will work well with the
version of the C++ library/compiler my customer/user is having?
Issue in detail: I mean, I compile my shared library with version 'X'
of a Std CPP compiler and customer tries to use with version 'Y' of
StdCPP compiler. And then, if 'X' and 'Y' versions of CPP compiler are
not compatible, then we get into trouble. We have hit this several
times with different gcc versions. Just wondering, what is the best/
cleanest way to solve/get-around this problem?

2) Sometimes it happens that you are working on a C++ based product
which already has millions of lines of code and then, one fine day a
requirement comes that a part of that chunk needs to be made accesible
to users through a shared library. Now, which you work towards
building that shared library, you may want to ensure that only symbols
that *should be* exported to users/customers, needs to be exported in
the shared library, all others un-wanted globals should not be
exported in the shared library to ensure we don't un-necessarily
pollute customer's namesapce with whole lot of our internal/global
symbols. (Note: Ideal solution for this issue, probably would be to
ensure that we should never pollute our implementation namespace at
all, in the first place, but as I said, you may not be the one who had
written all these code and it's a million lines code, and you don't
have the option/bugdet for re-arch/re-write!). For such a requriement,
if it was a C library we could typically use 'objcopy' in linux or -M
compiler option in Solaris, to make sure only a given set of symbols
(defined by us) are made global. But if it's a C++ library, I wonder
how to achieve this goal?
Issues: C++ symbols are mangled, so I would probably need to specify
those mangled names as an input to 'objcopy', but mangling varies from
compiler to compiler and platform to platform. With that this can
become a real maintenance headache.

Question: Is there a cleaner/better way to handle this?

Thanks in advance for oyour time and help!

Arijit
 
P

Phlip

I needed to build up a public API for an application at hand.

You cannot do any of this by guessing or planning. To create a public API, you
must write at least three projects, and port them to three different platforms
(linux, mac & pc) come to mind. Then you must configure your unit tests to run
simultaneously on each of the three platforms, each time you save your code. (I
have done this before, between Linux & PC, using Samba. Both platforms compiled
simultaneously into the same folders.)

Your nine projects should run all their tests each time you edit any of their
sources - both inside and outside the API boundary. And you write three
different projects to prove that your API actually solves problems for them,
flexibly.
The data I am modelling maps very well to object oriented design, so I
am little inclined towards a C++ public API (i.e. my deliverables
would be a <xyz>.hpp file which will have a bunch of pure virtual
functions forming the interface and a lib<xyz>.so which will basically
contain the implementation for those interfaces).

That's not what "pure virtual" means. It means the methods _don't_ have
implementations. If you go this route, you will simply need virtual methods.
However...

Why do you think the project will need an OO design? The point of OO is to
abstract and vary virtual methods behind common interfaces. Have you written any
sample code showing the best places for the virtual methods? They might not be
what you expect.

You might be safer - if your client actually _needs_ all these platforms - by
writing a C-style API. The C++ communities widely support this technique,
because most platforms enforce compatibility standards among simple functions.
By contrast, because C++ virtual methods must be very optimal, they enjoy fewer
standards. You might not be able to ship binaries, for example, and you might
have to ship live source code for your clients to compile.
But, I can think of 2 problems there:
1) How do I guarantee that my shared library will work well with the
version of the C++ library/compiler my customer/user is having?

By actually getting all the versions, like I said, and constantly testing them
as you change the code. If you make a change that you think is innocent, and if
one platform throws up a red flag, you can back out the change long before you
commit to it and invest more code around it.
Issue in detail: I mean, I compile my shared library with version 'X'
of a Std CPP compiler and customer tries to use with version 'Y' of
StdCPP compiler. And then, if 'X' and 'Y' versions of CPP compiler are
not compatible, then we get into trouble. We have hit this several
times with different gcc versions. Just wondering, what is the best/
cleanest way to solve/get-around this problem?

Have you surveyed your user population? Can you set up virtual Linuces with each
of these versions?
 
R

rabbits77

Hi

I needed to build up a public API for an application at hand.

The data I am modelling maps very well to object oriented design, so I
am little inclined towards a C++ public API (i.e. my deliverables
would be a <xyz>.hpp file which will have a bunch of pure virtual
functions forming the interface and a lib<xyz>.so which will basically
contain the implementation for those interfaces).
Can you write your public API in the most general
standards conforming way(no platform specific
calls)? If so, great! Do so!
You can be pretty much assured that it will work no
matter whether users try it with Visual C++ or g++
or whatever.
Then as an added bonus add on other language APIs on
top with SWIG. :)
 
P

Phlip

rabbits77 said:
Can you write your public API in the most general standards conforming
way(no platform specific calls)? If so, great! Do so!

That answers the wrong question. The API has two interfaces, one
programmer-facing and the other hardware-facing. The question was about keeping
the upper layer clean and portable.

Almost no program can do anything without platform specific calls - even tasks
as mundane as file reconnaissance are platform-specific. The OP is advised to
get into some full-featured portable platform, such as Qt or wxWindows, to get a
kit of all of those functions, readily ported and supported to a wide variety of
platforms. (Those platforms also come with nice GUI layers, which one can
exploit or ignore.)
 
T

Tony

Without even reading the body or you post, I suggest you consider "C++ Guru"
and expand your question to include the out of the box thinkers, for your
question is a design one rather than a language-specific one, at least to
some large degree, I think. When I think of "C++ Guru", I think of those
heavily knowledgeable of the C++ standard, who indeed are valuable (if not
temporary) walking/talking encyclonairies. Heavy knowledge in the C++
monstrosity leaves less "ROM" (subjective to some degree, but not mostly to
a high degree) for stuff outside of that narrow box (Ref, definition of
specialization: one learns more and more about less and less until they know
everything about nothing). Add that politics are more likely to be given
(knowingly or unknowingly via paradigmical thought), rather than unbiased
thought, and you have an answer that seemingly is good, but is just BS (at
worst).
 
G

Guest

Without even reading the body or you post, I suggest you consider "C++ Guru"
and expand your question to include the out of the box thinkers, for your
question is a design one rather than a language-specific one, at least to
some large degree,

this is about the sanest of Tony' recent posts. This probably *is* a
design
issue rather specifically a C++ problem. It certainly needs to deal
with
issues outside the C++ language.

but then...
I think. When I think of  "C++ Guru", I think of those
heavily knowledgeable of the C++ standard, who indeed are valuable (if not
temporary) walking/talking encyclonairies.

.... the great Word Salad came upon him and he was <snipped>
 
G

Guest

Posted to comp.programming in case they have any ideas on clean
public interfaces

I needed to build up a public API for an application at hand.

The data I am modelling maps very well to object oriented design, so I
am little inclined towards a C++ public API (i.e. my deliverables
would be a <xyz>.hpp file which will have a bunch of pure virtual
functions forming the interface and a lib<xyz>.so which will basically
contain the implementation for those interfaces).

as another poster pointed out your functions aren't virtual.
Do your APIs contain classes?

But, I can think of 2 problems there:
1) How do I guarantee that my shared library will work well with the
version of the C++ library/compiler my customer/user is having?
Issue in detail: I mean, I compile my shared library with version 'X'
of a Std CPP compiler and customer tries to use with version 'Y' of
StdCPP compiler. And then, if 'X' and 'Y' versions of CPP compiler are
not compatible, then we get into trouble. We have hit this several
times with different gcc versions. Just wondering, what is the best/
cleanest way to solve/get-around this problem?

it's probably insoluable in *any* language. Might it be better
to define an interface in terms of simple structures that are defined
as streams of bytes. Then provide some sort of RPC interface.

You might then look at ASN.1 or XML.

You loose the tight coupling between your application and the client
but gain the huge advantage of loosing the tight...


<snip>
 
M

Maxim Yegorushkin

I needed to build up a public API for an application at hand.

The data I am modelling maps very well to object oriented design, so I
am little inclined towards a C++ public API (i.e. my deliverables
would be a <xyz>.hpp file which will have a bunch of pure virtual
functions forming the interface and a lib<xyz>.so which will basically
contain the implementation for those interfaces).

But, I can think of 2 problems there:
1) How do I guarantee that my shared library will work well with the
version of the C++ library/compiler my customer/user is having?
Issue in detail: I mean, I compile my shared library with version 'X'
of a Std CPP compiler and customer tries to use with version 'Y' of
StdCPP compiler. And then, if 'X' and 'Y' versions of CPP compiler are
not compatible, then we get into trouble. We have hit this several
times with different gcc versions. Just wondering, what is the best/
cleanest way to solve/get-around this problem?

If you ship a C++ interface, you will have to provide a different
binary for every different version of OS and compiler your clients
use. This is because C++ ABI differs across compilers and even
compiler versions (e.g. gcc3 vs gcc4, sunCC vs. sunCC -
library=stlport4).

On the other hand, if you ship a C interface, you will only need to
provide different binaries for each OS. This is because C ABI is
stable and your clients can link against your C API using any compiler
for that particular OS.

Note, that you can do OO design in C. For example, a C++ intreface:

struct Foo
{
int doSomething(int);
};

Would look like this in C:

struct Foo; /* incomplete in the public API */
Foo* fooCreate();
void fooDestroy(Foo*);
int fooDoSomething(Foo*, int);

2) Sometimes it happens that you are working on a C++ based product
which already has millions of lines of code and then, one fine day a
requirement comes that a part of that chunk needs to be made accesible
to users through a shared library. Now, which you work towards
building that shared library, you may want to ensure that only symbols
that *should be* exported to users/customers, needs to be exported in
the shared library, all others un-wanted globals should not be
exported in the shared library to ensure we don't un-necessarily
pollute customer's namesapce with whole lot of our internal/global
symbols. (Note: Ideal solution for this issue, probably would be to
ensure that we should never pollute our implementation namespace at
all, in the first place, but as I said, you may not be the one who had
written all these code and it's a million lines code, and you don't
have the option/bugdet for re-arch/re-write!). For such a requriement,
if it was a C library we could typically use 'objcopy' in linux or -M
compiler option in Solaris, to make sure only a given set of symbols
(defined by us) are made global. But if it's a C++ library, I wonder
how to achieve this goal?

By exposing a C interface, so that your .so only exports the functions
of the public C API, all other symbols are made local or stripped.
(Don't forget to statically prelink your .so with a C++ run-time, so
that your C API .so does not have any unresolved C++ run-time
symbols).
 
C

cr88192

Hi

I needed to build up a public API for an application at hand.

The data I am modelling maps very well to object oriented design, so I
am little inclined towards a C++ public API (i.e. my deliverables
would be a <xyz>.hpp file which will have a bunch of pure virtual
functions forming the interface and a lib<xyz>.so which will basically
contain the implementation for those interfaces).

Question: Is there a cleaner/better way to handle this?

Thanks in advance for oyour time and help!

well, as a few others have said, and I am inclined to agree, my advice is
this:
make the external API be a C-based API.

then, it does not so much matter if the library is written in C, C++, or
some other language.
similarly, it will not matter if the client is written in C, C++, or some
other language (remember, not everyone uses C++, or is inclined to be bound
to using C++ for sake of a library...).


I will take it a little further, namely, the API should be an "abstract"
API, which in this context basically means:
no directly shared data structures (not as difficult, given it would likely
be C++ classes and a C-based API internally, but just as a point of
emphasis: it is rarely a good idea to have shared structures across API
boundaries);
instead, one can use handles, which are typically either integers or opaque
pointers (often "typedef void *myHandleType;" or similar...);
operations and mutations can still be performed, but typically this is via
some collection of abstract wrapper functions;
any data shared should be passed in buffers, and where ideally these buffers
should be no more complex than that of flat arrays (int, float, ...);
should complex data need to be passed, a personal recomendation is to use a
textual, or some other "cannonical" (as in, an established format)
serialization;
....

the reasons for the above are subtle, but important:
directly sharing data and structures between the client and the library is a
good way to make a mess;
in particular, it can tend to cause the client and the library to become
interdependent, and may often lead to minor changes to one side breaking the
other.

after learning this one from experience a few times over, I had adopted
this, arguably overly-strict seeming position (yes, shared data may seem to
make the API more "friendly" or allow tighter coupling, but very often, this
is more of an enemy than a friend...).

as for the buffer rule:
this is similar, and often it turns out this way in practice;
the more complex the passed data is, the more likely it is to need to be
changed later;
textual serializations partly sidestep this rule, as for a given data
complexity a textual format will almost invariably be drastically more
"generic" than an equivalent binary format (it is the case, don't expect me
to explain it, it relies on some esoteric properties...);
a "cannonical" format may also be an option, where this is usually a common
fileformat established for some specific use, for which it may make sense to
pass in a buffer (examples: JPEG, PNG, COFF, ELF, ...).

note (further justification of textual serialization):
it may seem like such a serialization would contribute a good deal of
overhead, however this has not been my experience in practice;
it can be noted that, in most cases where it is necessary to send complex
data, there is also typically a good deal of processing involved, which
would by far dwarf any real (noticable) cost of serializing the text, and
parsing it again;
it can be further noted that, in some cases, specially-crafted text formats
(and with specialized processing code), can match or exceed the raw
performance than could have been achieved via an equivalent binary format
(the key is that not all text needs to be "parsed", and infact, in many
cases it is possible to make what is, essentially, an ASCII-based binary
format...). similarly, although typically cryptic, there is an advantage
that a person familiar with the serialization can directly "read" the data
unaided (whereas a pure-binary format will almost invariably require a
hex-dump), which is particularly helpful with debugging.

granted though, this latter case is not to always be pursued, as it does not
scale so well to larger-scale complexities (at which point it may impose
similar problems to a plain binary format), however, often-times a good
portion of an otherwise more "generic" textual serialization can make good
use of individual components structured in this way (use with discretion,
however...).

note that I am not recommending that everything use XML or somesuch, as for
most tasks, this would be highly overkill, rather, usually a specialized
token-based format is sufficient.


and so on...


FWIW, I will add more:
given C has a single massive shared toplevel, it makes sense to "prefix"
function and type names with some prefix consistent to the library, and
hopefully unlikely to clash with any other library.

a personal style I use is:
libprefixCamelCase(...);
this style being (more or less) reserved for external API functions in my
case.


but, where internally I typically use:
LIBNAME_SubSys_CamelCase(...);
or just:
LIBNAME_CamelCase(...); //this more for smaller, more single-purpose, libs

similarly, in C++-based libraries, namespaces are a good option as well (for
internal use).


keeping this distinction may also better help one keep in mind what is
internal, and what is intended to be part of the external API.

I will also recommend that one actually put in effort and "design" the API,
whereas personally I don't feel as strongly about design WRT the internal
workings of a library (where, often, one may need to change and
rework/redesign the internals maybe numerous times before one has them "just
right", and so personally I would not recommend making the internals so much
"set in stone", whereas the external API is something which should hopefully
change sparingly, if at all...).

or such...
 
J

joshuamaurice

Write a C wrapper. If your interface were

    class Interface {
    public:
        virtual int f( double );
    };

    Interface* new_foo();

you could write a C wrapper as

    typedef struct Interface Interface;

    Interface* xyz_new_foo( void );
    void xyz_delete( Interface* );
    int xyz_f( Interface*, double );

and it would be accessible from many languages.
This

If you then wanted C++
users to have a more convenient interface, you could provide a client-side
wrapper for the C interface. :)

and this. Specifically, provide a small wrapper class in a header only
that implements itself in terms of the C API, and give this header to
clients. The class will be compiled by the client's compiler, and all
calls to your library will go through a stable C API. You gain the
stability of the C API and a nice C++ interface class.

Note that it's not always convenient, reasonable or practical to do it
this way, but many times it is.
 
C

cr88192

blargg said:
Not just binary, but conceptual interoperability. Almost all languages
have some means of calling C functions, and perhaps even passing and
returning structures. Lots of useful libraries can be presented in this
simple vocabulary. The dividing line between those that work well with a
C interface and those that need a C++ one is probably between libraries
that mostly provide data processing functions (like compression, media
file decoding) and rich data structures (like the STL, or most of boost).


yes, I will add something here:
I have noticed a similar effect before (although, granted, C++ is not my
primary development language), where many APIs seem best served by a clean
(or, almost sterile) and opaque API; yet others consist almost purely of
utility code, which need not have the same design.

for example, the API design which would work well on, say, a physics engine,
would not be the same as the one for, say, ones' geometric-math library
(even if they may typically be used in close relation to each other...).

so, yeah, the best design likely depends a lot on what the library does...



then of course, we have some people who could be paraphrased as "you must
all bow before the greatness of OO"...
 
J

Jorgen Grahn

You cannot do any of this by guessing or planning. To create a public API, you
must write at least three projects, and port them to three different platforms
(linux, mac & pc) come to mind. Then you must configure your unit tests to run
simultaneously on each of the three platforms, each time you save your code. (I
have done this before, between Linux & PC, using Samba. Both platforms compiled
simultaneously into the same folders.)

What you claim is provably false. What if it's a Windows-specific API?
Also, there is still no law which forces programmers to have unit tests.

Maybe what you mean is that it's hard to invent, implement and
maintain APIs, because you need to predict the needs of the users, and
then pretend to be the user when testing the API. That I would agree
with, strongly.

....
That's not what "pure virtual" means. It means the methods _don't_ have
implementations. If you go this route, you will simply need virtual methods.
However...

Why do you think the project will need an OO design? The point of OO is to
abstract and vary virtual methods behind common interfaces. Have you written any
sample code showing the best places for the virtual methods? They might not be
what you expect.

OO doesn't mean run-time polymorphism to everyone. Maybe he just means
that an API with classes seems like a good fit. (IIRC, Stroustrup
calls that an "object-based design".)

But that doesn't explain why he wants things virtual. Just to make it
clear: you do *not* need 'virtual' to distribute shared libraries, or
to distribute them in binary form only.
You might be safer - if your client actually _needs_ all these platforms - by
writing a C-style API. The C++ communities widely support this technique,
because most platforms enforce compatibility standards among simple functions.

Yeah, I vote for a C API too. They are widely understood, widely used,
and all serious languages can interface to them. (By all means, write
a C++ wrapper for it, too -- maybe the customer will use it, or maybe
you'll find weaknesses in the C API while doing it.)

/Jorgen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top