Abstract : this document explains how to write a plugin for integrating an unsupported compilers into Xcode (versions 3.0), to provide a fully integrated development platform for your preferred programming language. Plugins are currently available for : OCaml language, ADA language, Fortran language and targeting Symbian OS.
Jan. 2008 : updated for Xcode 3.0
Sept. 2006 : add a fortran plugin and a link to a plugin to develop for Symbian OS
Sept. 2006 : add documentation for GUI build settings and build rules
May 2006 : updated for Xcode 2.3
You may download theses pages as a ZIP archive for offline reading.
Sourceforge page for Xcode Plugins
Apple's free IDE, Xcode, only provides support for C(++), Objective-C(++), Java, Applescript and Makefile. Although it's possible to use a Makefile for other languages, I think it's more practical to fully integrate them through dedicated plugins.
At the time I wrote this page, Xcode already has a working plugin interface (it's even used by CoreData compiler/editor, CVS/Subversion/Perforce integration, GDB debugging…). However this interface is not yet public, because not really finished. According to Apple, it'll be public in future release but no real date is provided : developers just have to wait :-(.
With a lot of reverse engineering, I've successfully understood parts of this plugin interface and started to wrote a plugin for the Objective Caml language. Because many developers would like to write Xcode plugins for various programming languages, I've decided to publish the result of my reverse engineering work.
There's actually only informations about compilers, linkers and syntax highlighting plugins.
TODO
Xcode maintains internal arrays of many kind of objects used for every basic task. Each
object (or a list of object of the same kind) is defined by a NSDictionary stored in a property
list file. Xcode uses the key Class
to let you specify which Objective-C class will be
used to instantiate your object. Xcode also provide generic/default classes for each object types.
These object specifications are defined hierarchically (an object may be "BasedOn" another one, and then inherits all its properties) inside each specification kind :
*.pbfilespec
) : a list of files and wrappers types defined by their extension,
MIME type or magic code. You may see current available type in Xcode's preference window
(section Files). Generic types are : file, text, source code, compiled code, archive, audio,
image, video, folder, wrapper.*.pblangspec
) : a language description, used to define syntax highlighting rules,
auto-indentation rules, indexation and perhaps function name extraction (for the function popup
menu), auto-completion and other editor specific tasks.*.pbcompspec
) : a compiler description, used to describe a command line compiler
(like gcc
, osacompile
, javac
…), available build
setting for this compiler and how to parse its output.*.pblinkspec
) : a linker description, same as compiler specifications, but for
command line linkers (like ld
, libtool
…).*.pbprodspec
) : a product is the final file created by your project (a library, an
application…).*.pbpackspec
) : describes the structure
of a product.*.pbsetspec
) : defines generic (i.e. non attached to a compiler or linker) build
settings accessible from the Xcode GUI.*.pbarchspec
) : defines
architectures (ppc, m68k, i386…).*.pbplatspec
) : Xcode may be used
to compile code to different platforms, these specifications describe allowed architectures
for each platform and where to search header files and libraries.*.pbRTSspec
) : available runtime
system (native, java, applescript…)*.xcbuildrules
) : tell which source code file types may be compiled by a given
compiler.You will find Xcode's built-in definitions here :
/Developer/Library/PrivateFrameworks/DevToolsCore.framework/Resources/
The plugin code entry points are only custom classes specified by Class
keys in every
specifications stored in it's Contents/Resources
. If you don't use any Class
keys, you don't need to write any code. In this case, you may just put the specification files in
folder :
~/Library/Application Support/Developer/Shared/Xcode/Specifications/
A compiler (or linker) object is not used during the build task, but before it, when computing the dependency graph between source files, headers, compiled object files and the final product. This task is done when you open a project, add/remove a file from a target or save a edited file.
A compiler object is responsible of dependencies between source file (.c, .m…), header files (.h…) and compiled object file (.o). It also creates the command to generate the compiled object file.
A linker object is responsible of dependencies between compiled object files and the final product (an executable or library). It also generates the command used to link all object files.
When you request your project to build, Xcode just read the dependency graph and run your defined commands in the best order.
The file & command dependency graph of my OCaml Plugin created with Graphviz (click to enlarge).
Like the make
build system, Xcode use many environment variables. Theses variables
are divided into three big classes :
$(HOME)
, $(PRODUCT_DIR)
, $(PROJECT_DIR)
,
$(SYSTEM_LIBRARY_DIR)
… Theses variables are defined by Xcode.$(GCC_GENERATE_DEBUGGING_SYMBOLS)
,
$(GCC_OPTIMIZATION_LEVEL)
, $(PRODUCT_NAME)
,
$(HEADER_SEARCH_PATHS)
… The names are available in the description of each
setting. Theses variables are defined in the build setting window, according to compiler
and linker specifications.$(arch)
, $(variant)
, $(object_files)
…
Theses variables are defined by your own code, or Xcode internal one's.All variables are of type string. However, string lists may be simulated with space separated lists, as for command line tool arguments, and bool variables are simulated by using the two values NO and YES.
All Xcode strings (in build settings window, specification files, arguments of your plugin
methods), may contain variable substitution ("$(TARGET_PRODUCT_DIR)/$(PRODUCT_NAME)"
)
and even recursive substitution ("$(GCC_VERSION_$(arch))"
).
When expanding, you may apply some filters on the value of a variable : :quote
($(MYVAR:quote)
) to quote the value, :base
to extract the basename of a
file (= delete the extension), :identifier
to convert the value to a string suitable
for use as a C variable/identifier name.
To create an Xcode Plugin :
pbplugin
in the build settings window of the
target./Developer
LoadAtLaunch = YES
, XCPluginHasUI = NO
and XCGCReady = YES
keys to the Info.plist
file.*.pb*spec
) to the resources build phase./Developer/Library/PrivateFrameworks/DevToolCore.framework
framework to
your project.headers
to your project.XCODE_VERSION
macro to 30 (or 21 / 22 / 23, if you target Xcode 2.1 / 2.2 / 2.3).Xcode plugin.pbfilespec
file (you've downloaded it with the headers) to~/Library/Application Support/Developer/Shared/Xcode/Specifications/
.A Xcode plugin must be put in the following folder to be used (do not forget to restart Xcode after) :
~/Library/Application Support/Developer/Shared/Xcode/Plug-ins/
Feel free to have a look at my Objective-Caml plugin and Ada plugin source code and specification files.
TODO