Search Advanced Search Log In | Not a Member? Support ADC Home > Tools > This article provides an overview of the GNU Compiler Collection (GCC) from the Free Software Foundation and its use on Mac OS X. GCC is a free soft ware proj ect that has been used for many years to create software for UNIX and other platforms. Apple's developer tool Xcode (and previously, Project Builder) uses GCC under the hood for building executable images from source code. The GNU Debugger (GDB), a companion to GCC, comprises the foundation of the Xcode debugger. The examples presented here are command-line driven for several reasons: 1. Many UNIX devel opers are comforta ble with command-lin e based tool s. 2. Command-line tools provide a least common denominator for de velopers working on multiple platforms (including UNIX variants). 3. Many development projects are already set up with makefiles that simplify the build process. Rewriting those as Xcode project s may be time consuming and non-portabl e. 4. GCC is widely used in universities, and students new to Mac OS X programming will find the implementation on Mac OS X works very similarly to other platforms, with the addition of Apple-specific options. How GCC Works GCC consists of a set of tools that may be invoked using a single command plus options. True to the UNIX philosophy, the GCC tools perform specialized functions but work in harmony, passing the output from one tool as input to the next. GCC invokes these tools in a series of stages: compiler, assembler, and linker. 1. The compiler preprocesses, parses and analyzes source code; the output is a set of assembly language instructions. Preprocessing, which expands directives such as #include and #define , is performed by the compiler and not by a separate program. This is a change from previous versions of GCC. 2. The assembler produces object files from the assembly input. In the examples in this article the assemble r stage is included implicitly. 3. The linker transforms the object code into an executable image. Source and header file s may be any of several types, mos t common ly .c, .cc, .cp, .m, .mm, and .h on Mac OS X. GCC supports a variety of languages and extensions denoting source files, precompiled headers, source files not requiring preprocessing, and so on. Refer to the GCC manual for more information. A link is provi ded at the end of this article. Apple's vers ion of GCC is based on standa rd GCC relea ses and adds features that suppo rt Mac OS X. Some ofthese feature s get folde d in to the s tandard relea ses. Since GCC is an open source projec t it depends on its developer community for enhancements and fixes. Developers are encouraged to participate so that GCC can continue to evolve to support new languages, new processors, better optimization techniques, and so on. A Simple Example The Carbon Example (52KB) illust rates compiling , linkin g, and running a simple applicatio n that has no user inter face but does use a timer task . It install s the task in the Time Manag er queue. Every second the task trigge rs and invokes a Timer UPP, or callba ck functio n, defin ed in our source code. The callback simpl y logs the current time to stdout. The #include statement at the top of the file pulls in all other frameworks and headers used by the CoreServ ices
17
Embed
The GNU Compiler Collection on Mac OS X Development
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
8/6/2019 The GNU Compiler Collection on Mac OS X Development
This article provides an overview of the GNU Compiler Collection (GCC) from the Free Software Foundation and its
use on Mac OS X. GCC is a free software project that has been used for many years to create software for UNIX
and other platforms. Apple's developer tool Xcode (and previously, Project Builder) uses GCC under the hood for
building executable images from source code. The GNU Debugger (GDB), a companion to GCC, comprises the
foundation of the Xcode debugger.
The examples presented here are command-line driven for several reasons:
1. Many UNIX developers are comfortable with command-line based tools.
2. Command-line tools provide a least common denominator for developers working on multiple platforms
(including UNIX variants).
3. Many development projects are already set up with makefiles that simplify the build process. Rewriting
those as Xcode projects may be time consuming and non-portable.
4. GCC is widely used in universities, and students new to Mac OS X programming will find the implementation
on Mac OS X works very similarly to other platforms, with the addition of Apple-specific options.
How GCC Works
GCC consists of a set of tools that may be invoked using a single command plus options. True to the UNIX
philosophy, the GCC tools perform specialized functions but work in harmony, passing the output from one tool
as input to the next.
GCC invokes these tools in a series of stages: compiler, assembler, and linker.
1. The compiler preprocesses, parses and analyzes source code; the output is a set of assembly language
instructions. Preprocessing, which expands directives such as #include and #define , is performed by the
compiler and not by a separate program. This is a change from previous versions of GCC.
2. The assembler produces object files from the assembly input. In the examples in this article the assembler
stage is included implicitly.
3. The linker transforms the object code into an executable image.
Source and header files may be any of several types, most commonly .c, .cc, .cp, .m, .mm, and .h on Mac OS X.GCC supports a variety of languages and extensions denoting source files, precompiled headers, source files not
requiring preprocessing, and so on. Refer to the GCC manual for more information. A link is provided at the end
of this article.
Apple's version of GCC is based on standard GCC releases and adds features that support Mac OS X. Some of
these features get folded in to the standard releases. Since GCC is an open source project it depends on its
developer community for enhancements and fixes. Developers are encouraged to participate so that GCC can
continue to evolve to support new languages, new processors, better optimization techniques, and so on.
A Simple Example
The Carbon Example (52KB) illustrates compiling, linking, and running a simple application that has no user
interface but does use a timer task. It installs the task in the Time Manager queue. Every second the task triggersand invokes a TimerUPP, or callback function, defined in our source code. The callback simply logs the current
time to stdout.
The #include statement at the top of the file pulls in all other frameworks and headers used by the CoreServices
framework. The #include syntax is <frameworkName/headerFileName.h>. For example, Mac OS X Time Manager
tasks are handled by functions declared in Timer.h in the CarbonCore framework. Since CoreServices is an
umbrella framework, its single include file CoreServices.h includes CarbonCore/CarbonCore.h , which includes
CarbonCore/Timer.h and other appropriate headers. Put another way:
CoreServices/CoreServices.h includes CarbonCore/CarbonCore.h includes CarbonCore/Timer.h
This eases the burden on the programmer: rather than hunt down individual header files, you only need to include
one framework/header combination. You can include other frameworks as needed.
The top of the file contains declarations for several global variables, including the timer proc that gets installed inthe Time Manager queue. Once the application runs its course (five iterations), it disposes of the timer proc rather
than leave it installed.
main first calls an init function to setup the timer task, then loops waiting for a flag to set. After disposing of the
timer proc, main returns.
The timer proc (MyTimerProc) prints the current time and increments the counter. If the counter is below its limit,
MyTimerProc re-primes the timer task, otherwise it sets the done flag.
MyInit sets up the timer task, installs it, then primes it the first time.
You could write this application to instead provide a user interface with windows, menus, and so on. Simply
include the appropriate frameworks in the source code files.
#include <CoreServices/CoreServices.h>
void MyInit( void );
void MyTimerProc( TMTaskPtr tmTaskPtr );
Boolean gQuitFlag = false;
int gCount = 0;
TimerUPP gMyTimerProc = NULL;
int main( int argc, char *argv[])
{
MyInit();
while ( false == gQuitFlag ) {
;
}
DisposeTimerUPP( gMyTimerProc );
return 0;
}
void MyTimerProc( TMTaskPtr tmTaskPtr )
{
DateTimeRec localDateTime;
GetTime( &localDateTime );
printf( "MyTimerProc at %d:%d:%d\n", localDateTime.hour,
localDateTime.minute, localDateTime.second );
gCount++;
if ( gCount > 4 )
{
gQuitFlag = true;
}
else{
PrimeTimeTask( ( QElemPtr ) tmTaskPtr, 1000 );
}
}
8/6/2019 The GNU Compiler Collection on Mac OS X Development
To link against multiple frameworks, include each with its own -framework flag:
-framework CoreServices -framework Carbon
You can change compiler versions using gcc_select .
sudo /usr/sbin/gcc_select <version: 2, 3 or 3.x>
% sudo /usr/sbin/gcc_select 3.1
Default compiler has been set to:
Apple Computer, Inc. GCC version 1256, based on gcc version 3.1 20021003
(prerelease)
%
The -l flag lists available compiler versions.
% gcc_select -l
Available compiler versions:
2.95.2 3.1 3.3 3.3-fast
%
Run gcc_select -h to view additional options.
The compiler version matters because changes to the Application Binary Interface since Mac OS X v10.0 have
rendered C++ and Objective-C++ executables incompatible with earlier releases. However, C and Objective-
C programs still run the same. To build for 10.1 and earlier you must use version 2 of GCC for C++/Obj-
C++ applications and kernel extensions; version 2.95.2 was the GCC final release that shipped with Mac OS
X v10.1. GCC version 3.1 shipped with Mac OS X v10.2 Jaguar, and 3.3 with Mac OS X v10.3 Panther. Notethat if you mix languages in the application you should rebuild using the appropriate compiler version:
2.95.2 for Mac OS X v10.0 and v10.1, 3.1 for v10.2 Jaguar, and 3.3 for v10.3 Panther.
This list is not exhaustive. Look at the man gcc pages or one of the recommended references at the end of this
article for additional flags.
Makefiles
Makefiles help automate the build process. A makefile is typically named makefile or Makefile , and contains
commands for GCC regarding various targets and their dependencies. You can change the commands in the file
and, once it is working, not worry about forgetting a flag or option. This is very useful in the middle of the night
when you are tired and likely to make mistakes. Since GCC command-line entries can get very long you are lesslikely to invoke it incorrectly.
A makefile contains a set of targets. Each target may be dependent on other targets. Each target also includes a
command-line invocation preceded by a <tab> character. Here is the syntax:
8/6/2019 The GNU Compiler Collection on Mac OS X Development
The following example incorporates the test.c file used to generate the code optimization samples. The first
target, named test, depends on the target test.obj. If the output generated by target test.obj is newer than test, or
is not a file, then the make utility will run the appropriate command-line. In this case, invoke GCC and generate afile named test, using the file test.o as input.
Where does test.o come from? It is the output generated by the test.obj target. The input to target test.obj is
the file test.c. You can specify an output file using the -o option, or let GCC name the output file using the
pattern input-filename .o (lowercase letter 'o').
# The target named test depends on target test.obj.
# The command for target test:
# 1. invokes gcc,
# 2. generates a file named test (no extension) as output, and
# 3. uses file test.o as input.
#test: test.obj
gcc -o test test.o
#
# The next target name is test.obj. That is only its name.
# The name does not have to relate to what the target actually builds.
#
# This target builds object files from source.
# The command for test.obj instructs gcc to:
# 1. stop after compilation (no linking),
# 2. print verbose output, and
# 3. use the file test.c as input.
#
# The default output file name here will be test.o.
#
test.obj: test.c
gcc -c -v test.c
#
# Remove unwanted binaries, both the file named test and any .o files.
#
clean:
rm test *.o
#
# Generate assembly files. Useful for debugging.
#
asm0:
gcc -v -S -O0 -o test.O0.s test.c
asm1:gcc -v -S -O1 -o test.O1.s test.c
asm2:
gcc -v -S -O2 -o test.O2.s test.c
asm3:
gcc -v -S -O3 -o test.O3.s test.c
You invoke the make utility and specify the target, shown here from within a Terminal session. Any messages will
appear in the window.
$ make test
gcc -c -v test.c
Reading specs from /usr/libexec/gcc/darwin/ppc/3.3/specs
Thread model: posix
gcc version 3.3 20030304 (Apple Computer, Inc. build 1640)
8/6/2019 The GNU Compiler Collection on Mac OS X Development
If the make script is stored in a file named something other than makefile , pass the filename as a flag. Forexample, if the file was instead named test.mk, use:
make -f test.mk test
GNU Debugger
The GNU debugger (GDB) allows you to step through code, watch values, and monitor execution from the
command-line. Xcode uses GDB as the basis for its debugger. If you are using GCC you will want to also learn to
use GDB.
The first step is to compile your code with the -g flag: this includes GDB information in the object files. Without it
you will get strange errors when you try to use GDB to run your executable.
You invoke GDB using the gdb command along with the name of the executable to debug. GDB prints a banner,
after which it is ready to accept commands. The example used here is the Carbon application discussed earlier.
% gdb test
GNU gdb 5.3-20030128 (Apple version gdb-309) (Thu Dec 4 15:41:30 GMT 2003)
Copyright 2003 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "powerpc-apple-darwin".Reading symbols for shared libraries ... done
(gdb)
The best thing to start with is a breakpoint. This command sets a breakpoint on line 1.
(gdb) break 1
Breakpoint 1 at 0x1bd8: file test.c, line 1.
(gdb)
Begin execution by typing run . GDB prints information about what it is doing, then proceeds to and stops at the
breakpoint.
(gdb) run
8/6/2019 The GNU Compiler Collection on Mac OS X Development
[Switching to thread 1 (process 1254 thread 0x1603)]
Reading symbols for shared libraries ......... done
Breakpoint 1, main (argc=795571314, argv=0x65652f74) at test.c:12
12 {
(gdb)
The step command steps into a function.
(gdb) step
MyInit () at test.c:47
47 OSErr err = 0;
(gdb)
Use the print command to view a variable value.
(gdb) print err
$1 = 0
(gdb)
Step over a function using next.
(gdb) next
main (argc=1, argv=0xbffffbb0) at test.c:13
13 MyInit();
(gdb) next
15 while ( false == gQuitFlag ) {
(gdb)
Next, set a breakpoint in the callback (line 28), then continue execution. GDB pauses when execution reaches thebreakpoint. Check the date/time value. Note that GDB does its best when displaying the structure fields. The
structure looks a bit strange, so check the data type of localDateTime using the whatis command. This action
may be performed on any variable that is in scope, and is useful if you do not want to jump back to a code editor
window and look at the source code.
(gdb) break 28
Breakpoint 2 at 0x2b8c: file test.c, line 28.
(gdb) continue
Continuing.
[Switching to process 1080 thread 0x1203]
Breakpoint 2, MyTimerProc (tmTaskPtr=0xbffffd10) at test.c:28
28 GetTime( &localDateTim e );
(gdb) print localDateTime
$3 = {
year = 0,
month = 119,
day = 25967,
hour = 7018,
minute = 0,
second = 0,
dayOfWeek = 0
}
(gdb) whatis localDateTime
type = DateTimeRec(gdb)
Step through the next couple of lines and view the formatted output, which looks correct.
8/6/2019 The GNU Compiler Collection on Mac OS X Development
Under -O s the inner loop is much tighter, with only 1 store and add pair per iteration. A profiler can help you
determine whether this executes quicker than the -fast version.
_doubleTest:
...
L41: ; Top of outer loop
stw r9,36(r30)li r8,100
stw r10,32(r30)
mtctr r8
lfd f0,32(r30)
add r2,r11,r0
fsub f0,f0,f13
L46: ; Top of inner loop
stfd f0,0(r2) ; Store followed by add
fadd f1,f1,f0
addi r2,r2,8
bdnz L46 ; Branch to top of inner loop
addi r9,r9,1
addi r11,r11,800cmplwi cr7,r9,99
ble+ cr7,L41 ; Branch to top of outer loop
...
Specific optimizations
Loop unrolling
Expand a loop to include two or more iterations before checking the loop conditional. Use the flag -floop-
optimize .
Inlining functions
Functions with a line count below a certain threshold may have their instruction sequence substituted for thecorresponding function call. Since function calls involve overhead for stack frame setup, this may result in
faster (though longer) code. Turn on inlining using -finline-functions .
Strength reduction
Replace expensive operations with simpler operations. Use -fstrength-reduce .
For example, this loop:
for ( i = 0; i < 1000; i++ )
sum += i * 5;
generates this unoptimized code:
li r0,0
stw r0,40(r30) ; sum
li r0,0
stw r0,32(r30) ; i
... ; Top of loop
lwz r0,32(r30) ; Load i into r0
mulli r2,r0,5 ; Multiply r0 by 5, place result in r2
lwz r0,40(r30) ; Load sum
add r0,r0,r2 ; Add r2 to sum
stw r0,40(r30) ; Store new sum... ; Update i and branch to top of loop
This optimized version replaces the multiplication in the loop with an add:
8/6/2019 The GNU Compiler Collection on Mac OS X Development