Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you use the preprocessor for making a cross-platform library?

I want to use the same #ifdef approach used by WxWidgets , SDL etc. The only problem is I don't know how to use it.

Say I want to make a class that draws a rectangle. I want it to use cairo when on X11 platforms (i.e linux) and GDI on win32 platforms :

class graphics
{
void drawRect(int x, int y, int w, int h)
{
/*if on win32*/
HDC myHdc = ::BeginPaint(myHwnd,&mypstr);
::Rectangle(myHdc,x,y,w,h); 
::EndPaint(myHwnd,&mypstr);

/*if on x11*/
cairo_surface_t* s = cairo_xlib_surface_create(/* args */); 
cairo_t* c = cairo_create(s);
cairo_rectangle(c,x,y,w,h);
// etc. etc.
}
};

How would I use #ifdef or something else to do this?

like image 277
ApprenticeHacker Avatar asked Nov 10 '11 16:11

ApprenticeHacker


2 Answers

If you can, prefer to put platform specific methods into separate translation units. This will allow cleaner & more readable code and easier to develop and maintain. IMHO, the build process should determine which platform specific modules to incorporate.

For example:
rectangle.hpp:

struct Rectangle
{
  void draw(int upper_left_corner_x, int upper_left_corner_y,
            unsigned int length, unsigned int width);
}

Now the platform specific files:
rectangle_wx_widgets.cpp:

#include "rectangle.hpp"
void
Rectangle ::
draw(int upper_left_corner_x, int upper_left_corner_y,
            unsigned int length, unsigned int width)
{
// wxWidgets specific code here.
}

rectangle_qt.cpp:

#include "rectangle.hpp"
void
Rectangle ::
draw(int upper_left_corner_x, int upper_left_corner_y,
            unsigned int length, unsigned int width)
{
// QT specific code here.
}

main.cpp:

#include "rectangl.hpp"
int main(void)
{
  Rectangle r;
  r.draw(50, 50, 10, 5);
  return 0;
}

The above code has no conditional preprocessor directives. The main function draws a rectangle regardless of the platform. The specifics of the platform have been removed from main because they are not important. So, without changing any compiler switches or worrying about which preprocessor identifier is defined, one can see that main unconditionally draws a rectangle.

To draw using a wxWidgets platform, the build process would use rectangle_wx_widgets.cpp. To draw using QT, the rectangle_qt.cpp file would be used, but not both. As this illustration shows, no code is changed in order to produce code for either platform. One could tailor the build process so the command build wxWidgets would include the proper translation units. Thus passing a parameter to the build process generates the platform specific executable.

like image 53
Thomas Matthews Avatar answered Sep 21 '22 17:09

Thomas Matthews


cross-platform doesn't mean only unix vs windows. also, the predefined cpp directives may be compiler dependent. boost platform selection source code is a good start to see how this can be done the right way. see config/select_platform_config.hpp you may also want to take a look at cmake which sets some platform dependent defines

like image 34
user237419 Avatar answered Sep 21 '22 17:09

user237419