C++ Platform Support - c++

I am planning to make my C++ application compatible with Windows/Mac/Linux. At the moment I came up with this "code":
#if defined(_WIN32) || defined(WIN32) || defined(__WIN32__) || defined(__NT__)
#include <Windows.h>
#elif defined(__APPLE__) || defined(__MACH__)
#include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1
#error "IOS simulator is not supported!"
#elif TARGET_OS_IPHONE == 1
#error "IOS is not supported!"
#elif TARGET_OS_MAC == 1
//MAC??????
#else
#error "Unknown Apple platform!"
#endif
#else
#error "The platform you are currently using is not compatible!"
#endif
I don't know if I implemented Windows correctly, but at least I know what to include. So my questions are:
What do I need to import to use the Mac system library?
How can I implement linux support and what do i need to include to use his library?
I need the system libraries because later I planned to make a window class based on the system's libraries, I think you can do it for Windows but I am not really if you can do it sure on linux/mac.
Update #1:
Ok so I figured out which macros to use but what libraries should I include?
#if defined(_WIN32) || defined(WIN32) || defined(__WIN32__) || defined(__NT__) || defined(__CYGWIN__) || defined(__CYGWIN32__)
#define PLATFORM_WINDOWS
#include <Windows.h>
#elif defined(__APPLE__) && defined(__MACH__)
#include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1
#define PLATFORM_IPHONE_SIMULATOR
#error "Iphone simulator environment is not compatible!"
#elif TARGET_OS_IPHONE == 1
#define PLATFORM_IPHONE
#error "Iphone environment is not compatible!"
#elif TARGET_OS_MAC == 1
#define PLATFORM_MACOS
//what do I need to include here???
#endif
#elif defined(__ANDROID__)
#define PLATFORM_ANDROID
#error "Android environment is not compatible!"
#elif defined(__linux__) || defined(__linux) || defined(linux)
#define PLATFORM_LINUX
//what do i need to include here???
#else
#error "The platform you are currently using is not compatible!"
#endif

Related

using #if to run a function

I'm trying to run the expression _setmode only if I'm using Windows, and setlocale only if I'm using Linux, but I can't manage to make them work with a simple if-else inside a function due to Linux having errors with the Windows libraries, and vice versa.
#if defined(_WIN32) || defined(_WIN64) || (defined(__CYGWIN__) && !defined(_WIN32))
#define PLATFORM_NAME 0
#include <io.h>
#include <fcntl.h>
#elif defined(__linux__)
#define PLATFORM_NAME 1
#include <locale>
#elif defined(__APPLE__) && defined(__MACH__)
#include <TargetConditionals.h>
#if TARGET_OS_MAC == 1
#define PLATFORM_NAME 2
#endif
#else
#define PLATFORM_NAME NULL
#endif
#if PLATFORM_NAME == 0
_setmode(_fileno(stdout), _O_U8TEXT);
#endif
#if PLATFORM_NAME == 1
setlocale(LC_CTYPE, "");
#endif
If you write OS-dependent* code (as in this case), you can manage it at compile-time**. To do this, we need two parts:
Define OS-dependent constants (optional, if condition simple, this part can be omitted):
#if defined(_WIN32)
#define PLATFORM_NAME 0
#include <fcntl.h>
#include <io.h>
#elif defined(__linux__)
#define PLATFORM_NAME 1
#include <locale>
#endif
In needed place call OS-dependent code with preprocessor conditions:
#if PLATFORM_NAME == 0
//Windows code here
#endif
You can write more complex conditions:
#if PLATFORM_NAME == 0
//Windows code here
#elif PLATFORM_NAME != 0
//Non-Windows code here
#if PLATFORM_NAME == 1 || PLATFORM_NAME == 2
//Linux or unknown OS code here
#endif
#endif
See restrictions of conditions here
Tip: If your code have entrypoint (main function as example), you can call most of OS-dependent code at main if this help to reduce code. In library you can place OS-dependent code to dedicated source-file functions like there. Usage preprocessor-time code is good method for writing zero-cost runtime code because of preprocessor just remove all sources,if they're not met conditions.
* - or whatever-dependent 😃
** - more precisely, preprocessor-time
Source: GNU, Microsoft docs.

Chromium `debugger` equivalent, on `gdb` for Cygwin?

How do people trigger a breakpoint on gdb (for Cygwin, specifically) from the very source code?
Like when a JS script has the debugger word in it and Chromium dev tools trigger stop for debugging?
Here's how SDL2 implements this feature:
#if defined(_MSC_VER)
/* Don't include intrin.h here because it contains C++ code */
extern void __cdecl __debugbreak(void);
#define SDL_TriggerBreakpoint() __debugbreak()
#elif ( (!defined(__NACL__)) && ((defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__))) )
#define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" )
#elif defined(__386__) && defined(__WATCOMC__)
#define SDL_TriggerBreakpoint() { _asm { int 0x03 } }
#elif defined(HAVE_SIGNAL_H) && !defined(__WATCOMC__)
#include <signal.h>
#define SDL_TriggerBreakpoint() raise(SIGTRAP)
#else
/* How do we trigger breakpoints on this platform? */
#define SDL_TriggerBreakpoint()
#endif
The conditionals should probably resolve to __asm__ __volatile__ ( "int $3\n\t" ) on Cygwin.

Arduino platform compiler flag

Is there's any compiler flag to indicate the platform?
e.g:
#ifdef ARDUINO_UNO
....//code for uno
#elif ARDUINO_NANO
...//code for nano
#else
error("unknown platform");
#endif
In Arduino.h file, you can find the following preprocessor checks:
#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
...
#else
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__)
...
#endif
I never tried these, but do not I see why you will not be able to use them in your code as well.

How do I find the name of an operating system?

The questions pretty simple. I want want a function (C++) or method which will, on call, returun something like
"Windows" //or
"Unix"
Nothing fancy, I dont need the version numbe or anything. Just the os name. A quick google searc didnt turn up anything useful, so I thought I'd post this here
Since you can not have a single binary file which runs over all operating systems, and you need to re-compile your code again. It's OK to use MACROs.
Use macros such as
_WIN32
_WIN64
__unix
__unix__
__APPLE__
__MACH__
__linux__
__FreeBSD__
like this
std::string getOsName()
{
#ifdef _WIN32
return "Windows 32-bit";
#elif _WIN64
return "Windows 64-bit";
#elif __APPLE__ || __MACH__
return "Mac OSX";
#elif __linux__
return "Linux";
#elif __FreeBSD__
return "FreeBSD";
#elif __unix || __unix__
return "Unix";
#else
return "Other";
#endif
}
You should read compiler's manuals and see what MACROS they provided to detect the OS on compile time.
From the Poco source code:
Win32:
std::string EnvironmentImpl::osNameImpl()
{
OSVERSIONINFO vi;
vi.dwOSVersionInfoSize = sizeof(vi);
if (GetVersionEx(&vi) == 0) throw SystemException("Cannot get OS version information");
switch (vi.dwPlatformId)
{
case VER_PLATFORM_WIN32s:
return "Windows 3.x";
case VER_PLATFORM_WIN32_WINDOWS:
return vi.dwMinorVersion == 0 ? "Windows 95" : "Windows 98";
case VER_PLATFORM_WIN32_NT:
return "Windows NT";
default:
return "Unknown";
}
}
Unix:
std::string EnvironmentImpl::osNameImpl()
{
struct utsname uts;
uname(&uts);
return uts.sysname;
}

Undefined reference when building Metakit

I'm trying to use the Metakit library latest update, but I always get an Undefined reference in this piece of code:
bool c4_FileStrategy::DataOpen(const char *fname_, int mode_) {
d4_assert(!_file);
#if q4_WIN32 && !q4_BORC && !q4_WINCE
int flags = _O_BINARY | _O_NOINHERIT | (mode_ > 0 ? _O_RDWR : _O_RDONLY);
int fd = - 1;
if (GetPlatformId() != VER_PLATFORM_WIN32_NT)
fd = _open(fname_, flags);
if (fd == - 1) {
WCHAR wName[MAX_PATH];
MultiByteToWideChar(CP_UTF8, 0, fname_, - 1, wName, MAX_PATH);
fd = _wopen(wName, flags);
}
if (fd != - 1)
_cleanup = _file = _fdopen(fd, mode_ > 0 ? "r+b" : "rb");
#else
_cleanup = _file = fopen(fname_, mode_ > 0 ? "r+b" : "rb");
#if q4_UNIX
if (_file != 0)
fcntl(fileno(_file), F_SETFD, FD_CLOEXEC);
#endif //q4_UNIX
#endif //q4_WIN32 && !q4_BORC && !q4_WINCE
The strange thing (for me) is that, I get this linker error on this line: fcntl(fileno(_file), F_SETFD, FD_CLOEXEC); witch is used only for Linux. The #else part appears in gray, so I thought that code never compiles, so why do I get this undefined reference then ?
Any thoughts ?
PS: with my current older version I have no problem (2.4.6).
edit: I am on Windows and using Tornado (unfornatelly)
edit 2: this is how q4_UNIX is defiend:
#if defined (__MINGW32__)
#define d4_OS_H "win.h"
#elif defined (MSDOS) && defined (__GNUC__)
#define q4_DOS 1
#elif defined(unix) || defined(__unix__) || defined(__GNUC__) || \
defined(_AIX) || defined(__hpux)
#define q4_UNIX 1
#elif defined (__VMS)
#define q4_VMS 1
#elif defined (macintosh)
#define q4_MAC 1
#elif !defined (d4_OS_H)
#define d4_OS_H "win.h"
#endif
You say you are on Windows. This means that this line:
fcntl(fileno(_file), F_SETFD, FD_CLOEXEC);
should never have been compiled. This means that the #ifdef's are flawed.
You have three options for fixing:
Fix the defines so that this doesn't get compiled and gets preprocessed out instead.
Comment out the offending lines manually.
Try including <fcntl.h>, which might fix the issue. That is assuming you even have <fcntl.h>.