anatolyg
anatolyg

Reputation: 28278

Most standard way to select a function name depending on platform?

I am currently using the popen function in code that is compiled by two compilers: MS Visual Studio and gcc (on linux). I might want to add gcc (on MinGW) later.

The function is called popen for gcc, but _popen for MSVS, so i added the following to my source code:

#ifdef _MSC_VER
#define popen _popen
#define pclose _pclose
#endif

This works, but i would like to understand whether there exists a standard solution for such problems (i recall a similar case with stricmp/strcasecmp). Specifically, i would like to understand the following:

  1. Is _MSC_VER the right flag to depend on? I chose it because i have the impression that linux environment is "more standard".
  2. If i put these #define's in some header file, is it important whether i #include it before or after stdio.h (for the case of popen)?
  3. If _popen is defined as a macro itself, is there a chance my #define will fail? Should i use a "new" token like my_popen instead, for that reason or another?
  4. Did someone already do this job for me and made a good "portability header" file that i can use?
  5. Anything else i should be aware of?

Upvotes: 5

Views: 259

Answers (4)

eckes
eckes

Reputation: 67127

Instead of ending up with cluttered files containing #ifdef..#else..#endif blocks, I'd prefer a version using different files for different platforms:

  • put the OS dependent definitions in one file per platform and #define a macro my_popen
  • #include this file in your platform-agnostic code
  • never call the OS functions directly, but the #define that you created (i.e. my_popen)
  • depending on your OS, use different headers for compilation (e.g. config/windows/mydefines.h on windows and config/linux/mydefines.h on linux, so set the include path appropriate and always #include "mydefines.h")

That's a much cleaner approach than having the OS decision in the source itself.

If the methods you're calling behave different between windows and linux, decide which one shall be the behavior you're using (i.e. either always windows behavior or always linux behavior) and then create wrapper methods to achieve this. For that, you'll also need not only two mydefines.h files but also to myfunctions.c files that reside in the config/OSTYPE directories.

Doing it that way, you also get advantages when it comes to diff the linux and the windows version: you could simply diff two files while doing a diff on the linux and windows blocks of the same file could be difficult.

Upvotes: 0

Jens Gustedt
Jens Gustedt

Reputation: 78943

The way you are doing it is fine (with the #ifdef etc) but the macro that you test isn't. popen is something that depends on your operating system and not your compiler.

I'd go for something like

#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 2)
/* system has popen as expected */
#elif defined(YOUR_MACRO_TO DETECT_YOUR_OS)
# define popen _popen
# define pclose _pclose
#elif defined(YOUR_MACRO_TO DETECT_ANOTHER_ONE)
# define popen _pOpenOrSo
# define pclose _pclos
#else
# error "no popen, we don't know what to do"
#endif

Upvotes: 1

Phil Willoughby
Phil Willoughby

Reputation: 1734

  1. Better to check for a windows-specific define (_WIN32 perhaps) because mingw won't have it either. popen() is standardised (it's a part of the Single UNIX® Specification v2)
  2. No; so long as the macro is defined before its first use it does not matter if _popen() is not defined until later.
  3. No; what you have is fine even if _popen is a macro.
  4. It's been done many times but I don't know of a freely-licensed version you can use.

Upvotes: 3

user1481860
user1481860

Reputation:

  1. _MSC_VER is the correct macro for detecting the MSVC compiler. You can use __GNUC__ for GCC.

  2. If you are going to use popen as your macro ID, I suggest you #include it after, because of 3.

  3. If you #include it after stdio.h, it should work AFAIK, but better safe than sorry, no? Call it portable_popen or something.

  4. Many projects (including some of mine) have a portability header, but it's usually better to roll your own. I'm a fan of doing things yourself if you have the time. Thus you know the details of your code (easier to debug if things go wrong), and you get code that is tailored to your needs.

  5. Not that I know of. I do stuff like this all the time, without problems.

Upvotes: 1

Related Questions