Create automatic C wrapper for C++ library? - c++

Let say I have a C++ DLL. AFAIK, there is no widely-adopted ABI standard for C++, therefore to make sure it works and does not depend on the compiler of the target application I would need to wrap my library in a C interface.
Are there any tools that can automatically generate such interface? Would also be nice if they could generate wrappers around C interface to look as if they are original C++ objects, e.g.
Foo* f = new Foo(); // FooWrapper* fw = Foo_create();
f->bar("test"); // Foo_bar(fw, "test")
translates into C functions that are invoked in my library using generated C ABI. I understand that C++ is fairly complicated language and not everything can be easily wrapped in a C interface, but I was wondering if there are any such solutions that even support a subset of the C++ language (maybe with the help of some manually written IDL/XML files)?

there is no widely-adopted ABI standard for C++
I'm pretty sure that is a bit exaggerated - there aren't THAT many different compilers available for any given platform, so it would probably be easier to just produce a DLL for each vendor (e.g. Microsoft, GCC on Windows, GCC on Linux, Sun and GCC for Solaris, GCC for MacOS - CLANG is compatible with GCC as far as I know).
To add a C layer interface basically means that the interface layer must not:
1. Use any objects of that require special copy/assignment/construction behaviour.
2. Use any "throw" exceptions.
3. Use virtual functions.
across that interface.
It is my opinion that it's easier to "fix" the problems caused by "lack of ABI" than it is to make a good interface suitable for C++ use with a C interface in the middle of it.

If you want a way to make C++ code callable from other compilers/standard libraries, you can use cppcomponents from https://github.com/jbandela/cppcomponents. Full disclosure - I am the author of the library.
Here is a simple hello world example
First make a file called library.h
In this file you will define the Component
#include <cppcomponents/cppcomponents.hpp>
struct IPerson
:public cppcomponents::define_interface<cppcomponents::uuid<0xc618fd04,0xaa62,0x46e0,0xaeb8,0x6605eb4a1e64>>
{
std::string SayHello();
CPPCOMPONENTS_CONSTRUCT(IPerson,SayHello);
};
inline std::string PersonId(){return "library!Person";}
typedef cppcomponents::runtime_class<PersonId,cppcomponents::object_interfaces<IPerson>> Person_t;
typedef cppcomponents::use_runtime_class<Person_t> Person;
Next create library.cpp
In this file you will implement the interface and component
#include "library.h"
struct PersonImplementation:cppcomponents::implement_runtime_class<PersonImplementation,Person_t>
{
std::string SayHello(){return "Hello World\n";}
};
CPPCOMPONENTS_DEFINE_FACTORY(PersonImplementation);
Finally here is you main program (call it example1.cpp) that uses your implementation
#include "library.h"
#include <iostream>
int main(){
Person p;
std::cout << p.SayHello();
}
To build the program you will need to download cppcomponents (just clone from the git link above). It is a header only library and needs only a c++11 compiler.
Here is how you would build it on Windows
cl /EHsc example1.cpp /I pathtocppcomponents
g++ -std=c++11 library.cpp -o library.dll -shared -I pathtocppcomponents
where pathocppcomponents is the directory of cppcomponents.
I am assuming you have cl and g++ in your path.
To run the program, make sure library.dll is in the same directory as example1.exe and run example1.exe
This library requires fairly compliant c++11 support, so it needs MSVC 2013 Preview, and at least g++ 4.7. This library works on both Windows and Linux.

As far as I know the answer is no and you are supposed to handle this by yourself with a little bit of "hacking" and modifications, for example your t variable which is an std::string can possibly be "externed" to a C interface by t.c_str() because c_str returns a const char * which is a type that C understands without any problem at all.
I personally don't find C++ complicated, I can't see that "ABI issue" either, I mean nothing is perfect but you are externalizing to C your entire code base to "solve" this issue ? Just use C in the first place, also C it's no easy language to deal with either, for example in C there is not even the notion of "string", and problems that are trivial to solve in C++ while keeping everything type-safe, are really challenging in C if you want to meet the same goal.
I think that you are going a little bit too far with this, and you are complicating things, as it is now you have 3 + 1 main options on the most popular platforms :
libsupc++
libcxxrt
libc++abi
plus the whetever ABI is for the MSVC of your choice ( aka "only god knows")
for me, on linux, libsupc++ works very well, I'm following the libc++abi project and I don't see any big problem either, the only real problem with this is that llvm is basically an Apple oriented project for now, so there isn't that real and good support for the other platforms, but libc++abi compiles and works quite well on linux too ( although it's basically useless and pointless, on linux there is libsupc++ already.) .
I also would never ever use MSVC under Windows, in my opinion it's better to stick with a GCC-like compiler such as mingw, you got bleeding edge features, and you can simplify your codebase and your building phase a lot.

Related

Does C++17 provide a cross-platform scheme to record compiler version and options like Fortran?

Question
Modern Fortran offers a few cross-platform mechanisms to record the compiler version and settings used to build an application. What methods does C++17 have to capture this information? The book by Horton and Van Weert, Beginning C++17, does not appear to address this question.
The Fortran tools are surveyed below.
1. Access to compiler versions and options
The iso_fortran_env in Fortran provides a standard way to access the compiler version and settings used to compile a code. A sample snippet follows.
Code sample
program check_compiler
use, intrinsic :: iso_fortran_env, only : compiler_options, compiler_version
implicit none
write ( *, 100 ) "compiler version = ", compiler_version ()
write ( *, 100 ) "compiler options = ", trim ( compiler_options () )
100 format ( A, A, / )
stop "normal termination . . ."
end program check_compiler
Sample output
$ gfortran -o check_compiler check_compiler.f08
$ ./check_compiler
compiler version = GCC version 8.0.0 20170604 (experimental)
compiler options = -fPIC -mmacosx-version-min=10.12.7 -mtune=core2
STOP normal termination . . .
2. Probing and interacting with host OS
Fortran commands like execute_command_line, get_command, and get_environment_variable offer another route to record information at compile time.
What methods does C++17 have to capture this information?
None. The C++ standard does not even recognize the concept of "compiler" or "options"; there is merely the "implementation".
Furthermore, it would not really make sense, as different C++ files linked into the same program can be compiled with different options. And I'm not just talking about DLL/SOs; you can in theory statically link files that were compiled with different options or even different compiler versions.
Different compilers have ways to specify what version they are through macros. But each one has its own way to report this.
Searching the C++20 standard draft, which is available in GitHub, I find no results for closely-localted "compiler" and "version", nor have I found something like this looking at the text of the standard.
C++20 is at this time still very close to C++17, and certainly such a mechanism has not been removed, so I think it's pretty safe to say that there's no such thing in C++20.
Each compiler injects their own preproxessor tokens indicating itmwas compiled by them, and what version. These tokens are cross platform on compilers that compile on and to kore than one platdorm, such as icc, gcx and clang.
There are now standard defined ways to detect the existence of some srd header files. Boost has extensive headers that decode compiler capabilities based of a myriad of techniques.
__cplusplus in theory is defined to the standard version, but compilers lie.
The language standard specifies macros __cplusplus that encode the version of the standard that the compiler claims to support. It expands to 201703L on a C++17 compiler, 201710L on a C++14 compiler, and so on. It might also define _STDC and _STDC_VERSION. Beyond that, everything is a vendor-specific extension that you should look up in your compiler's manual.
Some but not all compilers, including GCC and Clang, predefine a macro named __VERSION__ that expands to a string describing the compiler version. You can check for this with #ifdef. Beyond that, many compilers contain macros that expand to version numbers, which you can stringify and concatenate. However, be aware that some compilers treat these as compatibility tests, and will claim to be a different compiler if you ask. In addition to its own version numbers, Clang defines __GNUC__, __GNUC_VERSION__ and __GNUC_PATCHLEVEL__ to indicate its compatibility with GCC, and the Windows version will also define _MSC_VER, _MSC_FULL_VER and so on in its Microsoft-compatiblity mode.
You could therefore create a complicated set of nested #elif blocks to recognize various compilers' version macros, but it could never be complete or forward-compatible.

Barebones C++ without standard library?

Compilers such as GCC and Clang allow to compile C++ programs without the C++ standard library, e.g. using the -nostdlib command line flag. It seems that such often fail to link thou, for example:
void f() noexcept { throw 42; }
int main() { f(); }
Usually fails to link due to undefined symbols like __cxa_allocate_exception, typeinfo for int, __cxa_throw, __gxx_personality_v0, __clang_call_terminate, __cxa_begin_catch, std::terminate() etc.
Even a simple
int main() {}
Fails to link with
ld: warning: cannot find entry symbol _start; defaulting to 0000000000400120
and is killed by the OS upon execution. Using -c the compiler still runs the linker which blatantly fails with:
ld: error in mytest(.eh_frame); no .eh_frame_hdr table will be created.
Is it a realistic goal to program and compile C++ applications or libraries without using and linking to the standard library? How can I compile my code using GCC or Clang on Linux? What core language features would one be unable to use without the standard library?
You will basically find all of your questions answered at osdev.org, but I'll give a brief summary anyway.
When you give GCC -nostdlib, you are saying "no startup or library files". This includes:
crti.o, crtbegin.o, crtend.o and crtn.o. Generally kernel developers only care about implementing crti.o and crtend.o and let GCC supply crtbegin.o and crtend.o by passing -print-file-name= to the linker. Generally these are just stubs that consist of .init and .fini respectively, leaving room for GCC to shove the contents of crtbegin.o and crtend.o respectively. These files are necessary for calling global constructors/destructors.
You can't avoid linking libgcc (the "low-level runtime library" (-lgcc) because even if you pass -nostdlib GCC will emit calls to its functions whenever you use it, leading to inexplicable linking errors for seemingly no reason. This is the case even when you're implementing/porting a C library.
You don't "need" libstdc++ no, but typically kernel developers want it. Porting a C library then implementing the C++ standard library from scratch is an extremely difficult task.
Since you only want to get rid of the "standard library", but keeping libc (on a Linux system) you're essentially programming C++ with just a C library. Of course, there's nothing wrong with this and you do you, but ultimately I don't see the point unless you plan on developing a kernel.
Required reading:
OSDev's C++ page - If you really care about RTTI/exception support, it's more annoying to implement than it sounds. Typically people just pass -fno-rtti or -fno-exceptions and then worry about it down the line or not at all.
"Standard" is a misnomer. In this context it doesn't mean "the library (set of functions, classes etc) as defined by the C++ standard" but "the usual set of libraries and objects (compiled files in a certain format) gcc links with by default". Some of those are necessary for most or even all programs to function.
If you use this flag, it's your responsibility to provide any missing functionality. There are several ways to do so:
Cherry-pick libraries and objects that your program really needs out of the default set. (Makes little sense as the result will most probably be exactly the same as with the default link flags).
Provide your own implementation of missing functionality.
Explicitly disable, through compiler flags, language features your program isn't using. I know of two such features: exceptions and RTTI. This is needed because the compiler needs to generate exceptions-related code and RTTI info even if these features are not explicitly used in this module.

How to make sure code (c++) written in Xcode can compile on other platforms?

I am a beginner was trying to do some C++ programming on Xcode. It works fine, but when I try to compile the same c++ file on my windows pc using VS, there were some errors. After I look at my code closely, there are really some stupid mistakes that I have made which caused the errors, but Xcode seemed to have ignored them...
My question is that is there any setting that I need to change to prevent Xcode from being so smart?
For example, the following code can actually compile in xcode:
#include <iostream>
using namespace std;
int main() {
if (true or false){
cout << "How is this possible? \n";
}
return 0;
}
There are also other cases where the code is actually wrong, but it can compile just fine is Xcode which is the annoying part and I want to disable that.
As far as I can see there is nothing wrong with your code.
The ISO C++ standard does not specify which standard headers are included by other standard headers. So, it is entirely possible that the version of iostream used by Xcode directly or indirectly includes ciso646. Whereas Visual Studio's version of iostream does not include ciso646. There are many similar cases with other headers. You just need to read the error messages and realize that your error (when you move your file to a different platform) is due to a missing header file.
It would be nice if writing portable code meant writing code in accordance with the C++ standard specification, but unfortunately that's not the case. Although there are various compiler options on various implementations which can help bring different implementations closer together, in general you will just have to bring the code into the target environment and actually test it there.
So ultimately writing portable code means you'll have to learn some subset of C++ that is accepted by all the implementations you want to target.
or is an 'alternative token' in C++, and VS is incorrect to reject it. There's no option in Xcode to disable support for alternative tokens. However VS has non-standard support for or as a macro using the header <ciso646>, and Xcode does have a header <ciso646> which does nothing (as the standard specifies). So you can write code which uses or and which works in both Xcode and VS by including this header.
#include <iostream>
#include <ciso646> // does nothing in Xcode, allows `or` in VS
using namespace std;
int main() {
if (true or false){
cout << "How is this possible? \n";
}
return 0;
}
Unfortunately VS can't support all of the alternative tokens through macros and so Xcode will still support some that VS doesn't.
There are also other cases where the code is actually wrong, but it can compile just fine is Xcode which is the annoying part and I want to disable that.
If you give specific examples then I can provide additional advice on how to write portable code.
Rather than changing your Xcode settings, I suggest cross-checking your code using another development environment.
If you're looking for something cheap and full-proof. Download a VirtualBox Windows VM, and run download Dev C++ (bloodhshed)
VS does not support or: you need to use || instead.
You can include some special files but it doesn't inject or sufficiently well into the language for it to work in all instances.
If you want to suppress use of or (and your compiler supports no better way)
#define it to something that emits a compiler error, for example
#define or OR
This at least means that the nature of the compilation errors will be identical on Xcode and VC.

boost::shared_ptr vs std::tr1::shared_ptr on multi os compilation

I have maintained different code for browser plugin(c++) for windows and mac system. The difference of the code is only for shared pointer.
In windows version I am using std::tr1::shared_ptr and on Mac version am using boost::shared_ptr.
Now I wanted to merge these code into one.I wanted to use std::tr1::shared_ptr in both code and maintain single source code but two different solution/project folder.
This browser plugin support up to OSX 10.5 onwards.Presently I am compiling in Xcode 4.6.2(Apple LLVM compiler).Basically I am Windows programmer and mostly work on Visual Studio.
My question is Will Mac Older version will support plugin with this change.Is this is a good idea ?
Please let me know whether boost is useful in this case.
First of all, boost::shared_ptr and std::tr1::shared_ptr are almost the same, but if you can you should use std::shared_ptr instead by enabling C++11 support (default on VS12 I think, to be enabled in clang / llvm).
The shared_ptr is a template class wrapping a pointer, thus the whole code is instanciated when you compile your program: the original class implementation resides in a header file which is incorporated in your translation unit (each separate file being built).
As such, you don't need any specific library to use shared_ptr (neither a .dll nor a .so or something else on Mac). So your program will run on any machine for which it has been built, you don't require additional library to run it.
You can also - for compatibility reason - use your own wrapper around the shared_ptr:
namespace my_code {
#if defined(_STD_TR1_SHARED_PTR)
using std::tr1::shared_ptr;
#elif defined(_STD_SHARED_PTR)
using std::shared_ptr;
#else
using boost::shared_ptr;
#endif
}
Thus you can access my_code::shared_ptr which will resolve to the appropriate type depending on the macros you define. Note that this only works if you use a compatible interface for all those types, but this should be the case.
Why don't you just test it? An easy first step would be to use a typedef to change the actual shared pointer definition under the hood:
namespace myNs{
#ifdef _USE_STD_SRDPTR
typedef std::shared_ptr sharedPtr;
#else
typedef boost::shared_ptr sharedPtr; //default to boost if no symbol defined
#endif
}
//in code replace old shared pointer usage
myNs::sharedPtr<Fruit> ourFruit( new Banana(WONKY) );
This way you can replace it in both code libraries, and change the underlying implementation whenever you want. You can add support for more options (e.g. the tr1 version) as you need to without changing your code. Of course all options need to have the same interface or the code won't compile.

Call C/C++ code form a fortran program in visual studio? (How to compile mixed C and fortran code in visual studio)

i am looking for a way, how i can integrate a c++ code with fortran code (i want simply call some C/C++ functions in the fortran code).
I have found some proposals for gcc or console compilers, but i have not any idea how to translate this approach to solve integrationproblem within the visual studio.
At the time I am thinking about creating a dll form c++ code and calling it from Fortran code.
Has someone already seen a solution? Or what is about overhead for calling function from dll? My fortran code transfers a lot of memory into C function, is there any problems, if i would solve this problem with dll?
thx.
PS
I am using Visual Studio 2008 Prof and Intel compilers 10
PPS
I think, i have to specify more concrete, what i want: i want to compile a fortran project in visual studio, which uses some C functions.
There is a new way to do this that has many advantages -- use the Fortran 2003 ISO C Binding. This is a standard and therefore largely OS and language independent way of interfacing Fortran and C (and any language that will use C calling conventions). Intel Fortran 11 supports along with numerous other compilers -- not sure about version 10. Using the ISO C Binding, you can match any C name (any case), don't have to worry about underscores (and variations between compilers) and can specify the types and calling methods (by reference, by value) for the arguments. Intel provides some examples in a folder with their compiler; there are also examples in the gfortran manual and a discussion of additional considerations for Windows. There are previous questions & answers here and on the Intel Fortran forum.
I integrated C and Fortran about 20 years ago and maintained this integration up to 5 years ago. The tricks I used were:
I noticed that the Fortran compiler puts all symbols in uppercase, so make sure your C/C++ functions are written in uppercase as well. To verify how symbols are put in the .OBJ file, use DUMPBIN.
The Fortran compiler does not understand the name-mangling done by the C++ compiler. Compile all your C++ functions using the C style convention (using extern "C")
Arguments in Fortran are always put on the stack using references/pointers. Therefore, use pointer-arguments in your C function.
To be honest, I gave up integrating C and Fortran when I switched to VS2005, so things might have changed since then. Nevertheless, it's still a good idea to use DUMPBIN to see what kind of symbols the Fortran compiler produces, and adjust the compilation of C/C++ sources to fit with that.
We do it where I work.
Assuming you are using the Intel Fortran compiler, look up its docs. By default Intel Fortran passes everything by reference and (I believe) uses the C calling convention, with an all caps identifier. Strings are a particular issue, as Fortran likes to pass the length as a hidden parameter, with a compiler setting for where it goes in the parameter list.
A wise programer doesn't rely on defaults (where a mistake can lead to undefined behavior), and will use the intel INTERFACE statements to specify calling convention, parameter passing, and the link name for the routine. The information on this page (ATTRIBUTES Properties and Calling Conventions) is a must-read. In particular you need it to understand the arcane rules for when and where string length parameters will be passed. I have a printout of it that I keep on my person. :-)
One other thing to note is that versions of VisualStudio past 6 don't like mixed Fortran and C projects. We solved the problem by creating custom project files calling out to makefile, but that's a PITA. I'd suggest going with the flow and using separate projects unless you are doing this a lot like we are.
Solution found:
solution link
i have had several problem with linking, which could be solved with adding in project properties.
code for testing:
#include <stdio.h>
extern "C"
{
void f()
{
printf("hi from c\n mega test");
}
}
fortran code
PROGRAM HelloWorld
use, intrinsic :: iso_c_binding
implicit none
interface
subroutine f( ) bind( c )
use, intrinsic :: iso_c_binding
end subroutine f
end interface
call f
END PROGRAM HelloWorld
on demand i can upload the testproject. thanks all, hopefully it was my last problem with c and fortran
I was able to build obj from fortran sources thanks to the Custom Build Tools of Visual Express 2010. I guess it is also possible in Visual Studio.
If you want to mix C and Fortran together, there is a good tutorial here. It was written for gcc compilers but you should be able to learn how to deal with name mangling easily.
Depending on the compiler, compiled subroutines/functions are Uppercase/lowercase, with a trailing underscore, with a leading underscore,... For a succesfull linkage, you could use dumpbin tools to see how the name appears in the objectfile.
An other way is to use iso_c_binding modules, but it is available with Fortran 2003 only.
This is the how it works with gcc and console
c.c:
#include <stdio.h>
void f_()
{
printf("Hi from C\n");
}
fortran.f90
PROGRAM HelloWorld
CALL f
END PROGRAM HelloWorld
Makefile
SRCDIR=.
all: clean release run
release:
gcc -c c.c -o c.out
gfortran -c fortran.f90 -o fortran.out
gfortran -o out.exe fortran.out c.out
run:
out.exe
clean:
#$(ZSHMAGIC) rm -rf *.exe core* *.o a.out 2> /dev/null
One other question: have i always add '_' after c-function name, which i use in the fortran program?