How to detect ABI at compile time? [closed] - c++

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
Is there a way to detect ABI in C/C++ at compile time? I know there are macros for OS and CPU architecture. Are there similar macros (or some other way) for ABI?

The notion of ABI is not known to standard specification like C11 or C++14. It is an implementation thing.
You could on Linux use feature_test_macros(7).
You could consider improving your build procedure (e.g. your Makefile, etc...). You might run some shell script detecting features (like autoconf generated configure scripts do). Notice that some C or C++ code (e.g. header files, etc...) might be generated at build time (for examples: by bison, moc, rpcgen, swig, ...), perhaps by your own utilities or scripts. Use a good enough build automation tool (with care, GNU make and ninja are able to deal with generated C++ or C code and manage their generation and the dependencies).
Don't confuse compilation with build; the compilation commands running a compiler are just parts of the build process.
Some platforms accept several ABIs. E.g. my Linux/Debian/Sid/x86-64 desktop with a Linux 4.13 kernel can run x86 32 bits ELF executable, x86-64 64 bits ELF, probably some old a.out format from the 1980s, and also x32 ABI. With binfmt_misc I can add even more ABIs. See x86 psABI for a list of several ABI documentations.
BTW, the current trend is to try writing portable code. Perhaps using frameworks like Qt or POCO or Glib (and many others) could hide the ABI details to your application.
In some cases, libffi might be helpful too.
In general, once you know your OS and your architecture, you can practically -most of the time- deduce the ABI.
If you really want your ABI, then a possible Linux specific way might be to run file(1) on the current executable. I don't recommend doing that, but you could try (using proc(5) to get the executable):
/// return a heap allocated string describing the ABI of current executable
//// I don't recommend using this
const char*getmyabi(void) {
char mycmdname[80];
int sz = snprintf(mycmdname, sizeof(mycmdname),
"/usr/bin/file -L /proc/%d/exe",
getpid());
assert (sz < (int) sizeof(mycmdname));
FILE*f = popen(mycmdname, "r");
if (!f) {
perror(mycmdname); exit(EXIT_FAILURE);
};
char* restr = NULL;
size_t siz = 0;
getline(&restr, &siz, f);
if (pclose(f)) { perror("pclose"); exit(EXIT_FAILURE); };
return restr;
} // end of getmyabi
/// the code above in untested
You could get a string like:
"ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked,"
" interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32,"
"BuildID[sha1]=deca50aa4d3df4d57bacc464aa1e8790449ebf8e, stripped"
then you need to parse that. You could also want to parse the output of ldd(1) or of objdump(1) on your executable, your ELF interpreter ld-linux(8), etc.... (or use some ELF parsing library for that).
I don't know how useful is that getmyabi function. I don't know what precise output is file giving (in all weird cases of various ABIs). I leave you to test it (be sure to compile your test program with all the ABIs installed on your system, so gcc -m32, gcc -m64, gcc -mx32, etc....); if possible test that on some non x86 Linux system.
If you just need to get your ABI at build time, consider compiling some hello-world executable, then run file (and ldd) on it. Have appropriate build rules (Makefile rules) doing that and parsing the output of those file and ldd commands.
(I am surprised of your question; what kind of application needs to know the ABI; most software needing that are compilers...; a strong dependency on a precise ABI might be the symptom of undefined behavior.)
Perhaps the hints given here might apply to your case (just a blind guess).
If you are writing some compiler, consider generating some C code in it then use some existing C compiler on that generated C code, or use a good JIT compilation library like LIBGCCJIT or LLVM. They would take care of the ABI specific aspects (and more importantly of low-level optimizations and code generation).
If you are writing a compiler alone and don't want to use external tools, you should in practice restrict yourself to one or a few ABIs and platforms. Life is short.
PS. I am not sure at all that ABI has a precise meaning. It is more a specification document than a defined feature of some system (or some executable). IIUC, the ABI specification did evolve (probably was not exactly the same 15 years ago).

Related

How to detect current operating system at runtime in c++?

I want to detect which operating system my .exe is being run on, so that I could perform specific operations depending on the underlying operating system. I want it to be just for windows and mac.
I want to detect which operating system my .exe is being run on
(notice that on MacOSX executable files are traditionally not suffixed with .exe; that convention is specific to Windows)
You cannot detect that in pure standard C++11 at runtime (so your question makes technically no sense), because the C++11 standard n3337 does not know about operating systems (some C++ source code may be compiled for the bare metal). I would recommend conditional compilation (e.g. #if) and using operating system specific headers (and configuring your build automation to detect them). Some C++ frameworks (boost, poco, Qt....) could be helpful, but you need to decide to choose one (they might try to provide some common abstractions above several OSes, but the evil is still in the details, e.g. file paths are still different on Windows and on MacOSX).
MicroSoft Windows has its own API, called WinAPI (which is only, in practice, used by Windows. Perhaps some day ReactOS would implement most of that API), documented here. MacOSX is more or less conforming to POSIX, which is a standard API about a family of OSes (but Windows don't care much about that standard).
If you want to learn more about OSes in general (a sensible thing to do), read for example Operating Systems: Three Easy Pieces (freely downloadable textbook).
In practice, an executable file compiled from C++ source code is specific to the operating system it is designed to run on, and its file format is also specific to some OS (e.g. PE on Windows, ELF on Linux, Mach-O on MacOSX...). So a Windows executable won't run on MacOSX and vice versa (the fat binary idea is out of fashion in 2018). You probably would adjust your build procedure (e.g. your Makefile, or with cmake, ninja, etc...) for your OS. That build procedure might (and often does) pass extra compilation flags (e.g. some -DBUILD_FOR_MACOSX compiler flag for your preprocessor, if building for MacOSX; then you might -in few places- use some preprocessor directive like #if BUILD_FOR_MACOSX in your C++ source code) specific to the target operating system. You could even customize your build so that on MacOSX some for-macosx.cc C++ file is compiled (and its object file linked into) your software, but on Windows you'll use some other for_windows.cc C++ file. Sometimes, the build procedure is flexible enough to auto-detect at build time what is the operating system (but how to do that is a different question. The GNU autoconf could be inspirational).
Once your build procedure has been configured for (or has auto-detected) your operating system, you could use preprocessor conditional facilities to #include appropriate system-specific headers and to compile calls to OS specific functions (such as POSIX uname) querying further at runtime about the OS.
Some compilers predefine a set of preprocessor symbols, and that set depends upon the target operating system and processor and of your compiler. If you use GCC, you might create some empty file empty.cc and compile it with g++ -c -C -E -dM (perhaps also with other relevant flags, e.g. -std=c++11) to find out which set of preprocessor symbols are predefined in your case.
Consider studying the source code (including the build procedure!) of some cross-platform free software projects (e.g. on github or somewhere else) for inspiration. You can also find many resources about multi-platform C++ builds (e.g. this one and many others).
There are various ways you could do it, like testing for the presence of a C:\Windows directory to detect Windows (edit: if the OS accepts a path like that at all then it's at least part of the DOS family), but none of them are foolproof. Here's one way (although it's cheating):
#include<boost/predef.h>
enum class OperatingSystem {
// ...
Windows
// ...
};
OperatingSystem DetectOperatingSystem()
{
#ifdef BOOST_OS_WINDOWS
return OperatingSystem::Windows;
#endif
}
Also, if you just want a name to show the user, then on POSIX systems you can use uname(2).
To solve this kind of problem you would need to check both at compile time and at run time. You are going to need different code for different both systems. You are going to need Windoze code to check the Windoze version and Mac code to check the Mac version.
You are going to have to use
#if defined ()
at compile time to check which of the two you are on. Then have separate code for each to get the version.

C++ Versions, do they auto-detect the version of an exe?

Okay so I know that there are multiple c++ versions. And I dont really know much about the differences between them but my question is:
Lets say i made a c++ application in c++ 11 and sent it off to another computer would it come up with errors from other versions of c++ or will it automatically detect it and run with that version? Or am I getting this wrong and is it defined at compile time? Someone please tell me because I am yet to find a single answer to my question on google.
It depends if you copy the source code to the other machine, and compile it there, or if you compile it on your machine and send the resulting binary to the other computer.
C++ is translated by the compiler to machine code, which runs directly on the processor. Any computer with a compatible processor will understand the machine code, but there is more than that. The program needs to interface with a filesystem, graphic adapters, and so on. This part is typically handled by the operating system, in different ways of course. Even if some of this is abstracted by C++ libraries, the calls to the operating system are different, and specific to it.
A compiled binary for ubuntu will not run on windows, for example, even if both computers have the same processor and hardware.
If you copy the source code to the other machine, and compile it there (or use a cross-compiler), your program should compile and run fine, if you don't use OS-specific features.
The C++ version does matter for compilation, you need a C++11 capable compiler of course if you have C++11 source code, but once the program is compiled, it does not matter any more.
C++ is compiled to machine code, which is then runnable on any computer having that architecture e.g. i386 or x64 (putting processor features like SSE etc. aside).
For Java, to bring a counterexample, it is different. There the code is compiled to a bytecode format, that is machine independent. This bytecodeformat is read/understood by the Java Virtual Machine (JVM). The JVM then has to be available for your architecture and the correct version has to be installed.
Or am I getting this wrong and is it defined at compile time?
This is precisely the idea: The code is compiled, and after that the language version is almost irrelevant. The only possible pitfall would be if a newer C++ version would include a breaking change to the standard C++ library (the library, not the language itself!). However, since the vast majority of that library is template code, it's compiled along with your own code anyway. It's basically baked into your .exe file along with your own code, so it's just as portable as yours. Also, both the C and C++ designers take great care not to break old code; so you can expect even those parts that are provided by the system itself (the standard C library) not to break anything.
So, even though there are things that could break in theory, pure C++ code should run fine on all machines that understand the same .exe format as the machine it was compiled on.

How can I compile C/C++ to a CP/M-86 executable (CMD)

I have this project: Compile a C/C++ program to a CP/M-86 executable (CMD-file) with a modern compiler. The target architecture is 16-bit x86. You may think I am crazy but I am doing this for fun and to learn about CP/M-86 and low level x86 programming in general.
I have little to no knowledge about x86 assembler programming but I have done a "Hello World" example that I can use ASM86 and GENCMD to generate a CMD-file. And it works. ASM86 is an assembler program for CP/M-86 that will generate a H86-file, that is (as far as I understand) Intel Hex Code. GENCMD reads this HEX-file and creates the CMD executable. CMD is the CP/M-86 equivalent of EXE executables know from DOS and Windows.
I have a "modern" tool that will compile and link 16-bit x86 NASM code and output a working CMD that I can run on my CP/M-86 machine - build completely on my Linux machine. However, I need a C/C++ compiler that will create this compatible NASM code. Or maybe some kind of a flat binary that easily converts into a CMD.
The second thing is system calls. I can probably make a print-like function using inline assembly and test that. For now I just want to compile this program, that does not do anything (and hopefully does not do any system calls?):
int main()
{
return 0;
}
C compilers do exist for CP/M-86 but these are very, very old and pretty much unusable. Especially if I want to do C++, like I really want to. So, it has to be done with a modern compiler like gcc or llvm-clang or something like that.
A last resort could be compiling a 16-bit DOS-compatible EXE and then do some system call translation... but that will be kind of cheating and still be quite time consuming.
How can I reach my goal? Thanks in advance. Any advice is appreciated :-)
How can I reach my goal?
If you have working C compiler, then I think llvm-cbe is what you are looking for. This is backend for clang-llvm (and any llvm compilers I think), it take llvm intermediate representation (IR) and convert it to C. So you can compile your c++17 code for any machine that has c compiler.
About
int main()
{
return 0;
}
On linux this code will call open/close (and other file related stuff), because of libc work with stdout/stderr/stdin,
also it call exit_group, I not sure about ms-dos, but it should it least somehow report exit code to system.

C Program Portability

As we know java is a platform independent language due to JVM it's program can run at any OS.
What about C/C++? could C/C++ exe run at any OS ? Could we have done something about this(Like write once run anywhere)? please clear my doubt about this.
Thanks
No - an executable is built for a specific operating system and hardware (CPU) architecture.
If you are carefull not to use any OS specific functions, or any assumptions about word size etc, then c++ source can be recompiled to run anywhere.
C and C++ are traditionally transformed into machine code for a particular CPU type/family, and packed within a format that a particular operating system can start.
There's nothing stopping anyone from making a C or C++ compiler that compiles code to run on a virtual machine in the same sense that java source code is compiled to byte code intended to run on the jvm. Someone
(The usefulness of doing so is another matter though, and e.g. while it's quite far from standard C++, C++/.CLI compiles a C++ like language to run on .NET)
Theorically, C programs only need a compiler that produce executable binaries for the target platform. That's why C is used in almost any embedded platform.
Practically, that require a separate compilation for each target platform.
C++ is another beast, clearly more complex and rich of features. Depending on the platform, you might or not have a compiler for C++, and if you have, embedded platform often require (for often non-obvious and sometimes critiquables reasons) that some C++ features are deactivated.
So with C++ you still "can" compile for any target platform, because it is a system programming language, like C (meaning that you're "close to the metal" with those languages).
However, there are still some problems you have to solve if you want to target some platforms :
some platform constructors will not allow you to run binaries on their platforms, only to sue their "secured" virtual-machine based language (whatever it is);
some platform constructors will provide compilers for their platforms, but with limited features, making them too poor to use for industrial developpement;
So theorically, C and C++ can run anywhere, if you compile for the target and that you use only cross-platform code/library.
In practice, it depends on the context.
Executable programs are platform and OS dependent. There are emulators in some OS that allows to run executables of other platforms (such as wine, dosbox etc. and of course VMWare) but this is an emulation/virtualization only.
Each operating system has it's own executable format, so you have to compile your C(++) program separately for each OS. If you use cross platform libraries, you can easily recompile your program without having to change your code a lot.

c vs c++ on solaris 9 platform question

I have a program that I am sharing with a third party. I will be providing a bin executable to them. It is written in c++ but uses some c as well. they are suggesting that it needs to be c only. Do you guys think this will be a problem since I will be compiling and building it on a sparc station that will somewhat match their system specs like solaris 9 and the chipset (32 or 64) depending on what they use?
is solaris 9 able to compile the c++ code that i used or do they need to add c++ runtime libraries on their end. I am using c++ std classes. in any event if i am building it all on my end why worry about what they have? its not a static/dynamic lib that i am sharing where i think that would come into play.
just curious since they are saying it needs to be a c compilation. I suspect if they are expecting a lib then perhaps I need to address that but if its just a executable then the system specs like os and chipset is all that matters?
if i am wrong in this assumption please let know where.
Worst case you can always statically link in the C++ runtime library.
If you are only sending them an executable, I don't see why the language makes any difference whatsoever. If you're also sharing code, of course, that's an entirely different story.
Since you're providing them with only an executable (no shared libraries), you shouldn't have too much trouble.
Just run a ldd command on your binary and see which C++ libraries it links against (you might see libstdc++ for instance, if you use g++); you should include those along with your executable. Don't rely on the user having them, they might be missing or might be incompatible. You will want to use the -rpath (linker switch) to make sure your binary will use the libraries you provide and not any library found in the system.
Also, it's better to compile on an older Solaris to provide compatibility, i.e. don't compile on Solaris 10 for Solaris 7, but on 7 for 10. You get the ideea...