Creating a Cross Platform Program Using C++ - c++

Let's say I have a simple project in MSVC++ 2010.
All there is in it is main.cpp, its code being something simple like this:
// include macros
#define WIN32
#include <FL/Fl.H>
#include <FL/Fl_Window.H>
#include <FL/fl_ask.H>
// main function
int main()
{
// init window
Fl_Window *window = new Fl_Window(250, 250, "Derp Window");
// show window, run window
window->show();
int result = Fl::run();
fl_message("Goodbye...");
// release pointers
delete window;
// return
return result;
}
It's easy to make a Windows compatible version, all I have to do is set the mode to release and the build it. But, as I have recently found out, the generated .exe file would not work on a Mac or Linux OS. This surprised me because all I am using is plain old c++ and FLTK, which is cross platform.
So, my question is, how would I take this code and compile it in a way that it would work on a Linux OS, and the a Mac OS? Or, is it even possible to keep the same code and compile it in a different way so it works on another OS? If it is not possible, what would I have to change?
PS. The code is pretty straight forward but if you're wondering the #define WIN32 is there because without it, the compiler freaks out about a missing header file, something like "X/X11.h"

The code is compatible, but that doesn't mean the generated binary will be. By and large, this is never the case.
Compilers take your code and translate it into lower-level code that your specific architecture and platform can understand, and Windows is not the same as Mac. This lower-level code has basically nothing to do with C++, FLTK or the compatibility promises of either of them.
The analogy here is that driving a car on the left hand side of the road is, mechanically, the same as driving a car on the right hand side of the road (so let's ignore things like navigation differences and the fact that you're probably steering in different directions), so your knowledge of how to drive a car fits both scenarios identically … but that doesn't mean you can simply plonk your car on the left hand side of the road in France or the United States. You'd cause a pretty gnarly accident. When you apply your knowledge of driving a car to a specific environment you have to fit that around the local rules of the road.
You can re-compile the same code under the target environment, or use a cross-compiler.

If you don't have access to a Linux or Mac OSX computer, you have to cross-compile it. To do this you have to either find a existing cross-compiler, you download the source to e.g. GCC and build it your self. Do some searching from "cross compiler" (or similar) and you will find some easy to follow tutorials.
If you do have access to a Linux or Mac, then just copy the code and build it in that environment. Be careful with Linux through, as different distributions have different versions of some libraries.
And finally, there are environments such as Wine which will allow Windows programs to run on other platforms.

If you use FLTK, you need to include its headers on every platform you compile your program, not just WIN32.
The error message you get about not finding X11/X.h is either caused by missing compiler flags (see 1), prerequisites that need to be included first (see 2), or missing headers (see 3).
Use fltk-config --cflags to get the required compiler flags, fltk-config --libs for the flags you need to pass to the linker.
Doesn't seem to apply here, but you might encounter libraries that require it.
If you use Ubuntu or Debian, install the X headers by executing apt-get install x11proto-core-dev, but that shouldn't be required if you already installed libfltk1.3-dev (or some other version), as it should pull in all the required dependencies. If you use a different distribution, make sure you have the X headers package installed.

The problem is probably the #define WIN32. From what you describe, I would guess that the FLTK library is using this to conditionally compile its headers either for Windows or for Unix (X). So you'd need it defined when compiling for Windows, and undefined when compiling for Unix. The usual way of handling such issues is to add a /DWIN32 option to the compiler invocation when compiling for Windows. You'll probably also have to do something to get the right libraries.
And FWIW: it's perfectly possible to design the library so that the header files work for both systems, without any conditional compilation. And if you want conditional compilation, you should probably use the system's predefined symbols (_WIN32, for example).

Related

Releasing a program

So I made a c++ console game. Now I'd like to "release" the game. I want to only give the .exe file and not the code. How do i go about this. I'd like to make sure it will run on all windows devices.
I used the following headers-
iostream
windows.h
MMSystem.h
conio.h
fstream
ctime
string
string.h
*I used namespace std
*i used code::blocks 13.12 with mingw
& I used the following library-
libwinmm.a
Thank you in advance
EDIT
There are many different ways of installing applications. You could go with an installer like Inno or just go with a regular ZIP file. Some programs can even be standalone by packaging all resources within the executable, but this is not an easy option to my knowledge for C++.
I suppose the most basic way is to create different builds for different architectures with static libraries and then find any other DLLs specific to that architecture and bundle it together in one folder. Supporting x86/x86-64/ARM should be enough for most purposes. I do know that LLVM/Clang and GCC should have extensive support for many architectures, and if need be, you should be able to download the source code of the libraries you use and then compile them for each architecture you plan to support as well as the compilation options you need to compile to each one.
A virtual machine can also be helpful for this cross-compilation and compatibility testing.
tldr; Get all the libraries you need in either static or dynamic (DLL) format. Check that they are of the right architecture (x86 programs/code will not run on MIPS and vice versa). Get all your resources. Get a virtual machine, and then test your program on it. Keep testing until all the dependency problems go away.
Note: when I did this, I actually had some compatibility issues with, of all things, MinGW-w64. Just a note; you may need some DLLs from MinGW, or, if you're using Cygwin, of course you need the Cygwin DLL. I don't know much about MSVC, but I would assume that even they have DLLs needed on some level if you decide to support an outdated Windows OS.

Where can I get windows.h for Mac?

I'm trying to compile a program on MacOSX that I originally wrote on a Windows OS. The program is a large C++ program with the OpenGL API among other things, totaling very many directories and files.
The compilation process at first had a problem with OpenGL for the Mac so I downloaded all the command line utilities of OpenGL for it to work. But as you might imagine, each C file within the OpenGL download had many preprocessors, each of which I in turn had to downloaded the dependencies for.
However, I have remaining one critical step: I receive a fatal error saying that windows.h file is not found. This seems something inherent to the Windows system (the windows.h file is nowhere to be found in my huge list of directories for the program), and the Mac does not seem to have an equivalent for windows.h (http://cboard.cprogramming.com/c-programming/96087-windows-h-mac.html).
Am I out of luck trying to compile this program for the Mac or can something be salvaged?
One thing you can do is create a dummy file called windows.h to satisfy the #include directive, then track down the missing typedefs, #defines, etc. one-by-one by looking at the compiler error log.
Windows.h is monolithic and includes about a hundred other Windows headers, but your program is not going to need all of those definitions. This assumes you are not using the Windows API directly, and only using simple things like DWORD. If your software is built using a framework like GLUT or GLFW that is entirely possible, but if you directly interface with WGL, you are going to have a lot of work ahead of you.
windows.h is provided by the Windows SDK, and implemented by the Windows OS itself.
You need to rewrite the program to not use Windows APIs.
Good luck.
You cannot get Windows.h for mac, it is Windows OS specific.
There are many alternatives to functions used in Windows.h on the other hand.

C++ Windows to Linux - what do I need to know?

I'm a bit stuck on trying to port my code from Windows to Linux. I created a Bluetooth based program, which seems to work in Windows well, that I need to get working in Ubuntu.
Unfortunately the computer with Linux on isn't mine, so I can't have any easy hacks using Wine or other massive compiler altering methods, I really need some advice on porting my code across so it'll be recognised and work in the different OS.
The computer does have code::blocks installed, which from what I understand is fairly useful in converting some things for cross-OS compiling, but I'm not getting too far.
The original code was written in Visual Studio 2013 and understandably it doesn't play nice in code::blocks. I'm getting a lot of 'can't find header' errors, but I don't think simply finding all the missing headers and copying them across will work (will it?).
I need some suggestions on the easiest, stand alone solution for my situation. By standalone I mean I want to get as much of the needed changes and libraries in my project, rather than change/install lots of things on the Linux machine.
I don't really know where to start and searches online don't seem to be too helpful.
Thanks!
First of all, I suggest you examine your Windows code, and use the PIMPL idiom (also here, here, ...) in your classes to isolate all platform-dependent code to separate windows and linux class implementations. Your main platform-independent class then will simply delegate to each implementation at compile time using preprocessor macros to include the appropriate platform implementation header and cpp files.
Beyond this, many runtime functions, as implemented in Visual Studio as either Microsoft-specific, or have been 'modified' and are no longer compatible or even have the same names as the standard ones you will find in linux. For these, you'll need to use a platform.h and platform.cpp file, with separate sections for the two operating systems, containing the missing functions in either macro-defined form (i.e. windows: strnicmp(), linux: strncasecomp() ), or write the missing ones yourself. Example:
// Linux section ...
#ifdef LINUX
#define strnicmp strncasecmp
#endif
The final work involved depends on how many windows-specific calls you have in your code.

Some things missing from gnu gcc compiler headers? (commctrl.h)

I have been using the gcc compiler with code::blocks ide, and have noticed there are some things missing in the commctrl.h which are:
PBS_MARQUEE and PBM_SETMARQUEE to set a progress bar to marquee animation style.
LVS_EX_DOUBLEBUFFER for a double buffer on a list view...
there are probably a lot more missing, but these are the ones i've noticed, and i need them!
i have downloaded the latest mingw libraries and they are still not in, the only place i can find them is in visual studios headers, but i don't want to use that
is there any way i can get them in gcc?
GCC does not do a good job of supporting Windows. This is a prime example of why. It's an excellent compiler. and on Unix boxes there's nothing else I'd ever use, because it's an excellent compiler, but...
MinGW simply does not include a few of the Windows headers, and for those that they do, they aren't always as up to date as the ones in the Windows SDK.
Finally, in order to support some bits of COM, GCC would need to be able to parse IDL, is not typically used on non-Windows systems is not currently supported by GCC.
Visual C++ Express (as well as it's compiler included in the Windows SDK) is free. What is your aversion to it?
The best way would be to contact either mingw.org or mingw-w64, which is a fork also supporting x64 targets. The latter are known to respond quickly and friendly to "missing features" requests. you can contact them on either the mailing list or forums or IRC (see link).
.... Scratch that. It seems my copy of the mingw-w64 commctrl.h header include these macros. I don't know if they work as expected, but give it a try. Downloads are linked on the page I linked to above. I would recommend personal builds by Sezero for completeness and ease of use. You should be able to replace your mingw folder with the one from the archive (make sure the gcc.exe et al match up).
Do you have the correct _WIN32_WINNT macro defined? It looks like they all need _WIN32_WINNT >= 0x0501.

Adding Boost makes Debug build depend on "non-D" MSVC runtime DLLs

I have an annoying problem which I might be able to somehow circumvent, but on the other hand would much rather be on top of it and understand what exactly is going on, since it looks like this stuff is really here to stay.
Here's the story: I have a simple OpenGL app which works fine: never a major problem in compiling, linking, or running it. Now I decided to try to move some of the more intensive calculations into a worker thread, in order to possibly make the GUI even more responsive — using Boost.Thread, of course.
In short, if I add the following fragment in the beginning of my .cpp file:
#include <boost/thread/thread.hpp>
void dummyThreadFun() { while (1); }
boost::thread p(dummyThreadFun);
, then I start getting "This application has failed to start because MSVCP90.dll was not found" when trying to launch the Debug build. (Release mode works ok.)
Now looking at the executable using the Dependency Walker, who also does not find this DLL (which is expected I guess), I could see that we are looking for it in order to be able to call the following functions:
?max#?$numeric_limits#K#std##SAKXZ
?max#?$numeric_limits#_J#std##SA_JXZ
?min#?$numeric_limits#K#std##SAKXZ
?min#?$numeric_limits#_J#std##SA_JXZ
Next, I tried to convert every instance of min and max to use macros instead, but probably couldn't find all references to them, as this did not help. (I'm using some external libraries for which I don't have the source code available. But even if I could do this — I don't think it's the right way really.)
So, my questions — I guess — are:
Why do we look for a non-debug DLL even though working with the debug build?
What is the correct way to fix the problem? Or even a quick-and-dirty one?
I had this first in a pretty much vanilla installation of Visual Studio 2008. Then tried installing the Feature Pack and SP1, but they didn't help either. Of course also tried to Rebuild several times.
I am using prebuilt binaries for Boost (v1.36.0). This is not the first time I use Boost in this project, but it may be the first time that I use a part that is based on a separate source.
Disabling incremental linking doesn't help. The fact that the program is OpenGL doesn't seem to be relevant either — I got a similar issue when adding the same three lines of code into a simple console program (but there it was complaining about MSVCR90.dll and _mkdir, and when I replaced the latter with boost::create_directory, the problem went away!!). And it's really just removing or adding those three lines that makes the program run ok, or not run at all, respectively.
I can't say I understand Side-by-Side (don't even know if this is related but that's what I assume for now), and to be honest, I am not super-interested either — as long as I can just build, debug and deploy my app...
Edit 1: While trying to build a stripped-down example that anyway reproduces the problem, I have discovered that the issue has to do with the Spread Toolkit, the use of which is a factor common to all my programs having this problem. (However, I never had this before starting to link in the Boost stuff.)
I have now come up with a minimal program that lets me reproduce the issue. It consists of two compilation units, A.cpp and B.cpp.
A.cpp:
#include "sp.h"
int main(int argc, char* argv[])
{
mailbox mbox = -1;
SP_join(mbox, "foo");
return 0;
}
B.cpp:
#include <boost/filesystem.hpp>
Some observations:
If I comment out the line SP_join of A.cpp, the problem goes away.
If I comment out the single line of B.cpp, the problem goes away.
If I move or copy B.cpp's single line to the beginning or end of A.cpp, the problem goes away.
(In scenarios 2 and 3, the program crashes when calling SP_join, but that's just because the mailbox is not valid... this has nothing to do with the issue at hand.)
In addition, Spread's core library is linked in, and that's surely part of the answer to my question #1, since there's no debug build of that lib in my system.
Currently, I'm trying to come up with something that'd make it possible to reproduce the issue in another environment. (Even though I will be quite surprised if it actually can be repeated outside my premises...)
Edit 2: Ok, so here we now have a package using which I was able to reproduce the issue on an almost vanilla installation of WinXP32 + VS2008 + Boost 1.36.0 (still pre-built binaries from BoostPro Computing).
The culprit is surely the Spread lib, my build of which somehow requires a rather archaic version of STLPort for MSVC 6! Nevertheless, I still find the symptoms relatively amusing. Also, it would be nice to hear if you can actually reproduce the issue — including scenarios 1-3 above. The package is quite small, and it should contain all the necessary pieces.
As it turns out, the issue did not really have anything to do with Boost.Thread specifically, as this example now uses the Boost Filesystem library. Additionally, it now complains about MSVCR90.dll, not P as previously.
Boost.Thread has quite a few possible build combinations in order to try and cater for all the differences in linking scenarios possible with MSVC. Firstly, you can either link statically to Boost.Thread, or link to Boost.Thread in a separate DLL. You can then link to the DLL version of the MSVC runtime, or the static library runtime. Finally, you can link to the debug runtime or the release runtime.
The Boost.Thread headers try and auto-detect the build scenario using the predefined macros that the compiler generates. In order to link against the version that uses the debug runtime you need to have _DEBUG defined. This is automatically defined by the /MD and /MDd compiler switches, so it should be OK, but your problem description suggests otherwise.
Where did you get the pre-built binaries from? Are you explicitly selecting a library in your project settings, or are you letting the auto-link mechanism select the appropriate .lib file?
I believe I have had this same problem with Boost in the past. From my understanding it happens because the Boost headers use a preprocessor instruction to link against the proper lib. If your debug and release libraries are in the same folder and have different names the "auto-link" feature will not work properly.
What I have done is define BOOST_ALL_NO_LIB for my project(which prevents the headers from "auto linking") and then use the VC project settings to link against the correct libraries.
Looks like other people have answered the Boost side of the issue. Here's a bit of background info on the MSVC side of things, that may save further headache.
There are 4 versions of the C (and C++) runtimes possible:
/MT: libcmt.lib (C), libcpmt.lib (C++)
/MTd: libcmtd.lib, libcpmtd.lib
/MD: msvcrt.lib, msvcprt.lib
/MDd: msvcrtd.lib, msvcprtd.lib
The DLL versions still require linking to that static lib (which somehow does all of the setup to link to the DLL at runtime - I don't know the details). Notice in all cases debug version has the d suffix. The C runtime uses the c infix, and the C++ runtime uses the cp infix. See the pattern? In any application, you should only ever link to the libraries in one of those rows.
Sometimes (as in your case), you find yourself linking to someone else's static library that is configured to use the wrong version of the C or C++ runtimes (via the awfully annoying #pragma comment(lib)). You can detect this by turning your linker verbosity way up, but it's a real PITA to hunt for. The "kill a rodent with a bazooka" solution is to use the /nodefaultlib:... linker setting to rule out the 6 C and C++ libraries that you know you don't need. I've used this in the past without problem, but I'm not positive it'll always work... maybe someone will come out of the woodwork telling me how this "solution" may cause your program to eat babies on Tuesday afternoons.
This is a classic link error. It looks like you're linking to a Boost DLL that itself links to the wrong C++ runtime (there's also this page, do a text search for "threads"). It also looks like the boost::posix::time library links to the correct DLL.
Unfortunately, I'm not finding the page that discusses how to pick the correctly-built Boost DLL (although I did find a three-year-old email that seems to point to BOOST_THREAD_USE_DLL and BOOST_THREAD_USE_LIB).
Looking at your answer again, it appears you're using pre-built binaries. The DLL you're not able to link to is part of the TR1 feature pack (second question on that page). That feature pack is available on Microsoft's website. Or you'll need a different binary to link against. Apparently the boost::posix::time library links against the unpatched C++ runtime.
Since you've already applied the feature pack, I think the next step I would take would be to build Boost by hand. That's the path I've always taken, and it's very simple: download the BJam binary, and run the Boost Build script in the library source. That's it.
Now this got even a bit more interesting... If I just add this somewhere in the source:
boost::posix_time::ptime pt = boost::posix_time::microsec_clock::universal_time();
(together with the corresponding #include stuff), then it again works ok. So this is one quick and not even too dirty solution, but hey — what's going on here, really?
From memory various parts of the boost libraries need you to define some preprocessor flags in order to be able to compile correctly. Stuff like BOOST_THREAD_USE_DLL and so on.
The BOOST_THREAD_USE_DLL won't be what's causing this particular error, but it may be expecting you to define _DEBUG or something like that. I remember a few years ago in our boost C++ projects we had quite a few extra BOOST_XYZ preprocessor definitions declared in the visual studio compiler options (or makefile)
Check the config.hpp file in the boost thread directory. When you pull in the ptime stuff it's possibly including a different config.hpp file, which may then define those preprocessor things differently.