2007-12-23

A Great Idea, Ruined by Apple and Microsoft

I was reading the GBADev forum yesterday and found an interesting thread about how people were getting around the problem of debugging when coding for the DS. It was such an interesting thread that I didn’t notice I’d missed both of the stops I could have got off at, and had to ride the train into the city centre and get a train back. Curses.

The idea goes something like this: If you can abstract away enough of the DS’ hardware, there’s nothing to stop you from writing a simple layer that will allow your DS project to run on the PC as a native application. Woopsi is itself basically a hardware abstraction layer, and all of its DS-hitting code is contained within Steven’s woopsifuncs files.

I decided that it would be easy to create a new “nds.h” file (containing all of the data type shortcuts from libnds) and create a new set of Woopsi functions targeted at another hardware platform. Obvious choice: SDL. If I can get Woopsi’s standard HAL pointing at SDL, Woopsi and any apps that use it will immediately run in Windows, on the Mac, on the Amiga, the GP2X, Linux…

Except, of course, both Microsoft and Apple have conspired against me to stop this happening. Getting SDL set up in Visual Studio looks to be needlessly complicated, so I went for Xcode instead. Easy to set up - just involves dragging the runtime library into the Frameworks folder, and copying over the templates.

However, Apple have played another hilarious trick with Leopard - if you upgrade Xcode from 2 to 3, you’ll find that trying to compile anything results in “duplicate symbol” errors. Nothing works.

That pretty much settles it. Leopard is a bloody nightmare if you perform an upgrade from Tiger - I’ve had endless problems with it - and I’ve got no choice but to wipe my laptop and reinstall the OS from scratch.

Comments

Jeff on 2007-12-23 at 23:16 said:

Well, that simple layer can’t be any less complicated than any of the DS emulators, unless you limit yourself enormously and its hard to see why you would bother. Just write native applications and be done with it.

Yes, its an attractive technical proposition to write a vanilla application layer, but you end up having DS look and feel on OSX, unless you spend more and more time messing with widgets - remember, Woopsi has some specific semantics of its own with respect to the way Gadgets communicate with their parents, and you’ll spend more and more time banging on Win32/Cocoa/Carbon widgets to make them match what WOopsi does - or worse, you’ll reengineer Woopsi to be more like them, and blow the limits that the DS has in stone (tiny screen, tiny RAM, singlt thread, etc)

As to 2->3, I had no problem - is it possible that you have some weird PATH setup, because they definitely messed around with the way that Xcode3 works so that you could have multiple parallel installs.

If your devkitpro installation gets anywhere near that (remember, it needs to mess with the PATH), I could see Xcode getting confused.

Jeff on 2007-12-23 at 23:20 said:

Remember too, that just because you abstract SDL, disk access (via libfat) is slightly different from , network access is slightly different, etc. Its hard to see what domain of application could be helped along by this process other than the most trivial.

Unless you are emulating the DS”s graphic hardware, sprites, 3d, etc… which a number of people are already trying to do with varying degrees of success.

Jeff on 2007-12-23 at 23:20 said:

AARRGGHH - “libfat is slightly different from <stdio.h>“

ant on 2007-12-23 at 23:26 said:

I’m not doing anything that complicated. It’s as simple as replacing the existing calls to libnds (pad, stylus, vbl, DMA_XXX) with calls to SDL. I’m not modifying any of the other files at all. Advantages: I can step through the Woopsi code using the Xcode debugger. Disadvantages: None!

It’s not going to be a GUI system using Carbon or Cocoa. I just want a way to be able to test the Woopsi logic without endless calls to Debug::printf(). I’m using an SDL screen as a DS simulator. As adding an SDL option is as simple as adding an #ifdef and replacing half a dozen functions, I’d be crazy not to try it.

ant on 2007-12-23 at 23:30 said:

Also, reinstalling is astonishingly easy. I backed everything up to a sparse image on my fileserver, booted the Leopard disk, and it churned away for an hour or so reinstalling. It then restored my user profile from my Time Machine backup, I copied the VMWare virtual disk back from the fileserver, and I’m up and running again. Amazing.

ant on 2007-12-23 at 23:41 said:

…But still getting “duplicate symbol” problems. In the bin with Xcode, then. Back to VC++.

ant on 2007-12-24 at 00:53 said:

Heh, it seems that it didn’t like the way I had a function in the .h file. Moved to the .c file, now works OK. A small amount of fiddling later, and - holy crap - a very green-tinged Woopsi screen running in an OSX window; no emulators involved, and I can step through the code.

ant on 2007-12-24 at 02:01 said:

I should mention that the point of this is to work out what’s going on with an unfathomable bug in the MultiLineTextBox gadget. I’m trying to get it to inherit from the ScrollingPanel. Everything works fine except scrolling text downwards. No idea why this should be, and as the textbox is the debug console, debugging is again impossible. If I can step through the code I’ll be able to sort it out in no time at all.

Jeff on 2007-12-24 at 02:35 said:

So, its probably worth noting for the Googlers out there that when Xcode 3 was reporting a problem of duplicate symbols, it was because … you had a function duplicated in your code, and not because of some problem in Xcode…

;-)

ant on 2007-12-24 at 08:06 said:

That’s the odd thing - the function wasn’t duplicated, it was in the .h file instead of the .cpp. The compiler definitely has a bug.

Steven on 2007-12-24 at 20:55 said:

Normally a function in an .h file causes duplicate function warnings / errors in most compilers that I know of… apart from devkit…

I know VS2005 kicks up a fuss if you declaire a variable in a header file that is linked to more than 1 file…

Jeff on 2007-12-25 at 01:02 said:

You need to differentiate between a function declaration and a function definition. You can put as many declarations as you like into .h files

The text in a .h file is copied, en-masse, into the compilation unit that results from any .c file that includes it. If you include that .h file into multiple .c files, then you will get multiple copies of the text being compiled, and if you define a function (that is, give it content) in a .h file, you will get multiple copies of the definition.

This is not a compiler bug, its the way that the C preprocessor has been defined since Kernighan and Ritchie first designed it.

In C++, if you use inline methods/functions, the LINKER is smart enough to recognise that you have used the same inline function twice and will merge them together, at link time.

This is one of my pet peeves about the all_gfx.c and all_gfx.h files - from comments you see on the intertubes about ‘don’t put graphics in .h files’, etc, people really don’t understand how the compilers work. You can put whatever you like into .h files, you just need to understand the consequences of your actions, which are (for the most part) completely predictable.

In the bad old days (I don’t think they do it now), Microsoft used to split their code libraries up into .inl files which they would include into .c files - this was a way of having insanely large, though still manageable source files that all compiled in one unit, and thus had access to the same static variables.

If I get a chance (its Christmas after all and I’m actually away from my computers), I want to have a go at rejigging the Woopsi build environment so that the custom arm7 part of the equation can be as simple as the rest currently is. One of the simplest ways to do that would be to have a WoopsiConfig.h file which people tweak, and then use that to drive what code gets included (to avoid the issue that the current makefiles insist on compiling everything in the source directories)

So, if you have


#define INCLUDE_WIFI

in your WoopsiConfig.h then the arm7/main.cpp would have


...
#if defined(INCLUDE_WIFI)
#include "woopsi_wifi.inl"
#endif

main()
{
#if defined(INCLUDE_WIFI)
    init_woopsi_wifi();
#endif

etc.

This is somewhat irrational in that it would be better to make the makefile sensitive to the defines instead, and just link or not link the libwifi.a (which is what I really intended and thats probably what I’ll do), but the same logic might apply to the AmigaXXX classes, etc. If you don’t want those things, then you don’t compile them.

ie, in you have


...
#if defined(AMIGA_LOOKANDFEEL)
#include
#include
...
#endif

Building a proper Woopsi library would also avoid that, but would not provide as much scope as compile-time function elimination. And my FileSelector class carries with it the need for libfat, which would mean that adding its .cpp file means you need to modify the makefile as well - better if it can be incorporated by just adding #define USE_FILE_SELECTOR to a config file and let the magic sort it out.

Of course, ever-more complicated makefiles is exactly what I complained about with PALib and devkitpro - my argument is that my approach would eliminate the need to be able to read makefiles to make simple changes like adding libraries.

(Personally, I’d rather ditch gmake altogether and build things with Python scripts - thats the way we are going with our multi-million line application at my day job, and its insanely easier to maintain)

Jeff on 2007-12-26 at 22:55 said:

Oh bugger, lots of <filename> missing from that previous post.

ant on 2007-12-27 at 08:47 said:

I think that if you sign up for an account with the blog you can edit your own comments and usually beat the spam filter.

OSX Lion | ant.simianzombie.com on 2011-07-21 at 19:12 said:

[…] the disaster that was Leopard’s release, I decided to wait before getting […]