According to Hoyle...
Mac OS X Development Beyond Leopard
by Jonathan Hoyle
jonhoyle@mac.com
macCompanion
November 2007
http://www.jonhoyle.com
"Beyond Leopard?!? But Leopard just came out!"
With Apple's
highly anticipated release of Mac OS X 10.5 Leopard
on October 26, there will
no doubt be a plethora of reviews, insights, tips for you to enjoy, including
many great ones here in macCompanion. Over the past few months, we have used
this column to help prepare developers for the Leopard-skinned future. These
include reviews of WWDC, Leopard,
Xcode and
Objective-C 2.0:
Now that
Leopard is in the present, it is sometimes easy to forget that there is still a
future ahead of us. There is always something just around the corner, and this
is one thing software developers like to pride themselves for being prepared.
Knowing what is coming next will often help you today, especially if you plan
to keep your application selling after release 1.0. For this reason, we will
take this month to get greedy and look just beyond the confines of this first
release of Leopard. So if you will indulge me this momentary breach of
etiquette, come as we take an unauthorized tour into the near future of Mac OS
X software development.
Xcode & gcc
With the
release of Mac OS X 10.5 Leopard, Apple has provided Mac software developers
the latest upgrade of its tools: Xcode 3. Although there are significant
improvements in the IDE, its main component - the
gcc compiler - remains unchanged
from Mac OS X 10.4 Tiger. As
you may already be aware, gcc is an open source
compiler, part of the Gnu Project sponsored by the
Free Software Foundation.
Apple's Xcode is the integrated development environment which wraps this
compiler. Like gcc, Xcode is free; unlike gcc, however, Xcode is neither
cross-platform nor open source.
Xcode 2.x and 3
each use gcc version 4.0.1 as its default compiler, although Xcode does allow
you to change to the older gcc 3.3 compiler. Given that gcc 3.3 is not fully
ANSI C++ compliant and lacks
Intel compatibility,
there is little reason for the modern developer to consider gcc 3.3 today. And even when version 3.3 was
the default compiler in Xcode 1.5, Apple was recommending its developers to
compile and test against gcc 4.0, so as to be prepared for the future. After
having taken great pains to migrate Mac programmers to gcc 4, Apple decided not
to make any compiler changes with Xcode 3 and Leopard, at least not just yet.
Despite Apple's
hesitation to move beyond version 4.0.1, Gnu has been moving forward quite
readily on its own. Version 4.0.x updates continued in 2005, with 4.1 released
in February 2006, and a succession of 4.1.x updates following thereafter. 4.2
was released in March of this year, with 4.2.1 in July, and 4.2.2 in October.
How long will Apple stay with version 4.0.1 before it decides to upgrade? This
is of course a matter of speculation, but it seems likely that they will be
making a move sooner rather than later. Those Mac developers who have signed
up for their free ADC membership
can see for themselves Apple's early progress on gcc 4.2.
Apple's GCC 4.2 Developer Preview is still under non-disclosure, so I cannot speak
on its particulars. (Irrespectively, a shrewd Google search will yield a lot
of information for you, including the
GCC
4.2 Developer Preview Release Notes themselves.) You'll note that the NDA on Apple's Developer Preview is not much
of a limitation, since gcc 4.2 is itself freely available and all information
on it is open source. Essentially, I can speak on Xcode 3, and I can speak on
gcc 4.2. I just can't speak of gcc 4.2 within Xcode 3. Therefore, I will
address these separately.
Xcode 3: Where We Are Today?
Xcode 3 has
added a number of powerful new features that improve the Mac development
experience. The most notable is the change of the default debugging format from
STABS to
DWARF. In STABS, debugging
information is hard-linked into the actual
executable itself, grossly inflating file size. The STABS portion was typically
much larger than the executable itself and thereby slowing down the link
process. DWARF only soft-links this information, making the executable much
smaller. DWARF has the additional benefit of being more C++ friendly, handling
namespaces and inline functions much better. For those still using Xcode 2.3
or higher, DWARF is available (although off by default); my recommendation is
for all users of Xcode 2.x to switch to DWARF now.
Another
significant improvement in Xcode 3 is its increased security. One such security
improvement is the inclusion of what's called
stack canaries. A
stack canary is essentially a guard band between scope variables and a
function's return addresses. Object size checking is also done, by replacing (for example)
strcpy()
with a parameter checking equivalent. Neither of these
new features is turned on by default, presumably to allow for better code
optimization. You must turn these items on in your Project settings. Perhaps
the best guard against malicious programs is in the treatment of space allocated by
malloc(). In
previous versions of Xcode, such space could be used to hold executable code. This is
rarely desired by the developer, and is often exploited by malware copying
unpleasant code into its contents. With Xcode 3,
malloc()-ed
space is non-executable by default.
Developers who wish to make it executable memory must use
mprotect().
gcc 4.2: Where We Will Be Tomorrow
When looking at
the change list of gcc over the past two years, we see that there are a number
of improvements made since the version found in Xcode. As stated earlier,
learning about these and other changes in gcc do not require you to sign an NDA
with Apple, as Gnu publicly releases this information as gcc evolves. Gnu has
separate web pages documenting the modification history for gcc 4.0.x (last
version 4.0.4), 4.1.x (latest 4.1.2), and 4.2.x (latest 4.2.2 as I write this),
and you can view them here:
gcc 4.0 Release History
gcc 4.1 Release History
gcc 4.2 Release History
Rather than
parrot what is already in these release notes, I wish to concentrate on two of
the more powerful features in 4.2 that will likely make your life easier as a
Mac developer. Both of these are changes specific with 4.2.x.
Parallel Universe
One of the most
powerful new features of gcc 4.2 is OpenMP,
a multiprocessor support capability. Consider a
simple, yet common, task of summing the values of two arrays and placing their
sum in a third array:
// traditional looping
for (i = 0; i < numItems; i++)
z[i] = x[i] + y[i];
Suppose this
code snippet lives in a critical area of code which you would like to optimize.
Machines with multiple processors could be used to parallelize this loop, by
dividing the work across each processor core, dramatically improving
performance. Unfortunately, writing the threading code and implementing
the required mutexes to support this is quite complex, and would necessarily require
a great deal of code debugging to get it right. If such a procedure is needed
throughout different areas of the code, it gets even worse.
With OpenMP,
however, only two directives need be added:
// parallelize this loop
#pragma omp parallel shared(x, y, z, chunk) private(i)
{
#pragma omp for schedule(dynamic, chunk) nowait
for (i = 0; i < numItems; i++)
z[i] = x[i] + y[i];
};
The first
#pragma
informs the compiler which data objects are being shared across threads, and which is private. The second
#pragma
handles the for loop chunking. This code is an order of
magnitude easier to write, as it simply directs the compiler to perform the
parallelization. OpenMP is implemented by POSIX
threads, thus making
them quite solid and secure.
Visible Means of Support
In today's
software development arena, programmers find that they must increasingly
interface with other programs. Frequently, this means loading
shared libraries
written by other people. Unfortunately, not all of these programs are well
modularized, and global functions and variables used in these libraries may
have generic names which can easily clash. Such short-sighted authors declare
global variables, functions and types with names like
Max,
Run,
or even something as embarrassing as an iterator named
i. Even
careful programmers may accidentally hit upon name collisions unintentionally. Authors of
shared libraries must struggle between using obscure names unlikely to clash and keeping their source
code readable.
The C++
mechanism for avoiding such name collisions is to encapsulate related the objects into a
namespace. Items
within one namespace do not collide with
identically named ones in another. A minor risk that remains is that two libraries might use the same
namespace name, such as
MyNamespace
(although this is admittedly pretty unlikely). The bigger problem is simply that many developers are
either ignorant of, or simply too lazy to use
namespace's.
In gcc 4.0,
this problem can be handled with the
visibility
attributes. A library author can define his structure with the
__attribute__((visibility("hidden")))
suffix, as so:
// hidden structure
struct InternalStruct __attribute__((visibility("hidden")))
{
int field1;
double field2;
void *field3;
};
When doing so,
no one outside this library will see this structure defined, The gcc 4.2
compiler takes this functionality to the next level by automatically hiding
functions and variables associated with a hidden type:
void MyFunction(InternalStruct &inStruct); // automatically hidden
std::vector<int> myVector1; // not hidden
std::vector<InternalStruct> myVector2; // automatically hidden
C++ developers may even hide entire
namespace's
in the same manner:
namespace hiddenSpace __attribute__((visibility("hidden")))
{
// Implementation details all hidden
}
Anonymous
namespace's
have no name, so it is not possible to associate it with this
visibility
attribute. To address this, gcc 4.2 implicitly makes all items in an anonymous
namespace
(as well as items outside it that use them)
static:
// anonymous namespace
namespace
{
struct MyStruct
{
... // struct definition here
};
}
void foo(MyStruct &myParm); // static
std::vector<MyStruct> myVector; // static
These visibility improvements do more than simply avoid name collisions. It also
significantly improves linker performance, as fewer variables and types need be
considered whilst building your program.
Stepping into the Future
These are
merely two of the more significant changes found in gcc 4.2. There are of
course many others. If you wish to be prepared for the next generation
compiler, my recommendation is to keep an eye on gcc 4.2. It is this author's
opinion that it will not be long before the future will (once again) be here.
Coming Up: With the advent of Mac OS X 10.5 Leopard, Apple has
finally put the nail in the coffin for Classic Mac OS. Or
have they? Next month, we look at how you can still run Classic on Leopard. See you in 30!
http://www.maccompanion.com/macc/archives/November2007/Columns/AccordingtoHoyle27.htm
Herokuapp Web Archive