Wednesday, March 23, 2016

The Working Subset

<< Prev: Plugging Gaps       Next: The Linker >>

So with enough #defines in place, I started to feel like I ought to be able to make some progress on getting the code into a compile-able state. The big problem remaining was the huge number of Linux API calls. They were in all sorts of areas: PCI devices, memory allocation, DMA mapping, synchronization, queueing, network packets, and so on. I started keeping a list of the specific missing API calls I saw as I looked through the code, and it quickly grew to 60+ items. And that's just what I came across; not making an effort to look at ALL the code.

On the one hand, it felt a little like I could attack these one group at a time. I had already spent some time on PCI device registration and recognition in OS X, for instance, so maybe I could work on migrating of removing the PCI code from the Linux driver. And by removing, I mean defining it out, like this:
#define DISABLED_CODE 0
...
#if DISABLED_CODE
#include <linux/pci.h>
#include <linux/pci-aspm.h>
#endif

That DISABLED_CODE was defined in the basic porting header file, so I could use it anywhere. The advantage over commenting out or just plain removing the code in question would come when I tried to update to a newer driver release. It should be more obvious what was mine (as opposed to comments, which may have been in the original), and it would be a smaller and more manageable change to the source code than removing entire blocks. That's the thinking, anyway.

So I embarked on a process of:
  1. Run a build in the IDE
  2. Find the lowest-hanging fruit among the errors
  3. Fix them
  4. Repeat
If they weren't Linux macros that I hadn't migrated yet, they were often Linux header files that I'd exclude like the above. Fix and repeat. It seemed to go on and on. Eventually I started getting some more meaningful issues, but if I ignored them I could keep going.

At some point, I noticed how I had been doing this for a pretty long time, and I still kept coming across different files. So then, I really took another look at the source tree. Even removing the older DVM firmware directory, I had about 100 files. Plus 10 more header files I had pulled in from Linux in their entirety (mainly wireless-related stuff), and one more grab bag file of individual constants or structs that I pulled in where it didn't make sense to take the whole file.

I tried estimating how long it would take me to not just cover the low-hanging fruit, but actually get all that code to compile. Fix all the easy errors. Understand what all those API calls were actually doing. Find the equivalent calls in OS X. Make any changes needed when there wasn't a one-to-one correspondence. Probably over a hundred APIs in a hundred files, before I could even BUILD. Ridiculous.

So then I thought, maybe I can just flat-out comment out or define away every single statement that doesn't compile, build the rest, and then go back and fix things to actually work. Except that was going to rely on me actually fixing everything. If I just commented or defined it out, I'd have to be diligent about putting TODO messages in or something. And if I overlooked going back to fix just one, it could all be for naught, leading to outright failures, or perhaps worse, subtle bugs. It was really easier to use the compile failures as the indicator of what still needed attention.

So then, I thought, what if I could exclude the files I haven't worked on yet from the build, and get some small core of this thing to build, and then grow it out from there? I could add back one file at a time as I needed the functionality and had the time to fully migrated it.

Turns out, this is very doable. In AppCode, you can remove source files from the build in bulk (while leaving them in the project) by going into the project settings (right-click the top-level project in the project view), and then selecting the "target" on the bottom left. That gave a list of all the included .cpp and .c files, and it was easy to select all the C files and hit the big minus button. Bam! Problem solved!

Well, not quite, but close. First, I needed to figure out how to add them back in as needed. That turned out to be right-click on the .c file in the project view, select Manage Targets, and check the target again. With that established, I left them all out of the build.

Then I needed to figure out what my small core of buildable code was going to be.

I started with my .cpp files and the headers just for them. I had gotten rid of my old header file with the PCI device listings, in favor of one that was much closer to the original source. So I brought that header in, which in turn brought in a variety of others. I still had some cleanup to do in that chain of headers, but much less.

And then, voila! It built! All I had to do was remove all the actual C code from the build, and I was back to where I was before... Which from a certain point of view is not much progress. Except now I had a project full of Linux sources, some of which I was actually using, and I had managed to remove code from my original effort, and I would be able to build out from there. So it felt like a solid step.

Once again, I had surprised myself with working code.

OK, let's not get too far ahead of ourselves. With building code. But surely if it built, then it would run... (cue drumroll)

Sample Code

The code and project as of this point is on GitHub here. All the code is still present, but if you open the project in Xcode or AppCode, you'll find all the C files excluded from the build -- so most of them probably still won't compile.

<< Prev: Plugging Gaps       Next: The Linker >>

No comments:

Post a Comment