AddThis Social Bookmark Button

Print

PBTOMAKE -- Xcode to Unix

by Jim Schimpf
04/20/2004

When I develop on Mac OS X, I usually use Xcode. Others obviously differ about use of IDEs, but I prefer it. I do have a problem when I wish to move an app from Mac OS X to other flavors of Unix or Linux.

In most cases I am not attempting anything exotic, these are usually CLI applications (e.g. a very specialized Lua interpreter with extensions for my company's products). So moving to Linux or Unix should be pretty much a slam-dunk, simply recompiling the code. Easy in theory, but if the app in question has over 100 files in many different directories, and if it's an Xcode project, then there's no makefile.

I had hoped that Xcode would include this export function. But it doesn't, so I've created a free, open-source version and have made it available to you.

PBTOMAKE Version 3.0 Program

This program is freeware with source and can be downloaded from the (PBTOMAKE Download page). It is run from the terminal command line and as an example run on its own project you would get:

[Pandoras-Computer:TOMAKE10.3/Source/PBTOMAKE] jim% pbtomake -i PBTOMAKE.pbproj
PRODUCT IS [pbtomake]
FILE [main.cp]
FILE [CPBPROJ.cp]
FILE [CBufFile.cp]
FILE [CSymbol.cp]
FILE [CLexFile.cp]
FILE [CpbxLexFile.cp]
FILE [CTokFile.cp]
FILE [CMaker.cp]
FILE [cutil.cp]
FILE [CBufFile.h]
FILE [tgtypes.h]
FILE [CSymbol.h]
FILE [CLexFile.h]
FILE [CpbxLexFile.h]
FILE [CTokFile.h]
FILE [CMaker.h]
FILE [base.h]
FILE [cutil.h]
FILE [CPBPROJ.h]
[Pandoras-Computer:TOMAKE10.3/Source/PBTOMAKE] jim% 

This would generate the makefile in a file called makefile. The makefile could be used by typing make in this directory. This would build a new copy of pbtomake using make and the makefile.

[Pandoras-Computer:TOMAKE10.3/Source/PBTOMAKE] jim% make
/usr/bin/g++3  ../main.cp -c -I../BASE_PC -I../BASE_PC/Dohickies -I.. -o main.o
/usr/bin/g++3  ../CPBPROJ.cp -c -I../BASE_PC -I../BASE_PC/Dohickies -I.. -o CPBPROJ.o
/usr/bin/g++3  ../BASE_PC/CBufFile.cp -c -I../BASE_PC -I../BASE_PC/Dohickies -I.. -o CBufFile.o
							:
							:
/usr/bin/g++3  ../CMaker.cp -c -I../BASE_PC -I../BASE_PC/Dohickies -I.. -o CMaker.o
/usr/bin/g++3  ../BASE_PC/cutil.cp -c -I../BASE_PC -I../BASE_PC/Dohickies -I.. -o cutil.o
/usr/bin/g++3  \
	main.o\
	CPBPROJ.o\
	CBufFile.o\
	CSymbol.o\
	CLexFile.o\
	CpbxLexFile.o\
	CTokFile.o\
	CMaker.o\
	cutil.o\
	-o pbtomake
[Pandoras-Computer:TOMAKE10.3/Source/PBTOMAKE] jim% 

Pretty simple really, and the idea is you run pbtomake on your project, copy the whole development tree to the Linux/Unix box and run make there. You will then get the application built on the other system without having to manually build a makefile with all the dependencies. Obviously you still have code porting to do, since, for example, under Mac OS X you link to frameworks while under other systems you have other ways. There's lots of other details involved in porting the code but pbtomake saves you the initial messy task of listing all the files and their paths to manually build a makefile.

makefile Details

The makefile created by the program is very simple and has everything specified. It doesn't use rules or any other shortcuts. Each and every file is separately specified, along with all the include files. So the file created for this run is:


###################################################
## Makefile for pbtomake
# Creator [Xcode -> Makefile Ver: 3.00]
# Created: [Sat Mar  6 07:48:15 2004]
#
###################################################
#
# Macros
#
CC = /usr/bin/g++3
CC_OPTIONS = 
LNK_OPTIONS = 
#
# INCLUDE directories for pbtomake
#
INCLUDE = \
		-I../BASE_PC\
		-I../BASE_PC/Dohickies\
		-I..
#
# Build pbtomake
#
pbtomake : \
		main.o\
		:
		:
		cutil.o
	$(CC) $(LNK_OPTIONS) \
		main.o\
		:
		:
		cutil.o\
		-o pbtomake
#
# Build the parts of pbtomake
#

# Item # 1 -- main --
main.o : ../main.cp
	$(CC) $(CC_OPTIONS) ../main.cp -c $(INCLUDE) -o main.o
	:
	:
# Item # 9 -- cutil --
cutil.o : ../BASE_PC/cutil.cp
	$(CC) $(CC_OPTIONS) ../BASE_PC/cutil.cp -c $(INCLUDE) -o cutil.o
##### END RUN ####

Program Internals

Project Files

The Xcode project file PBTOMAKE.pbproj is really a directory containing two files (do ls -als PBTOMAKE.pbproj at the command line):


 0 drwxrwxrwx   4 jim  staff    136  7 Mar 07:03 .
 0 drwxrwxrwx  18 jim  staff    612  6 Mar 07:51 ..
 40 -rwxrwxrwx   1 jim  staff  17747  7 Mar 07:03 jim.pbxuser
 32 -rwxrwxrwx   1 jim  staff  12708  7 Mar 07:03 project.pbxproj

The jim.pbxuser is the per-user settings for the project and things like window positions. The project.pbxproj file is the description of the files and how to build the application. This is the file that pbtomake works on.

Knowledge of project.pbxproj is just by observation and trying to extract the information to build the makefile. If someone reading this has deeper knowledge I would appreciate hearing from you. The general form of both of these files is a hierarchical structure based on keys/values and lists. The usual form of things are:

	key	=	value; 

Now value can either be a single string/name or a list and lists written as:


	{
		thing,
		thing1,
		:
	};

Where thing and thing1 can be either simple values or embedded lists.

Project File Analysis

The code modules CBPROJ, CpbxLexFile, CTokFile, CLexFile and CBufFile are used to convert the file structure into an in-memory tree representation of the text structure in the file. The form here is the conventional breaking of the input file into tokens; then CBPROJ.cp builds the tree.

For example, reading key = value; would turn into the token list:


	  key	  =	 value	  ;
	<Token>	<LINK>	<Token>	<END>

CBPROJ reads each of these tokens, stacking them up until a trigger is found, In this case an <END> token, meaning that we have come to the end of an element in the file. It then can package up the key and value as an element and attach it to the tree structure of the file it's building. If you want to see this tree use the -debug option of pbtomake and it will be dumped out.

Besides the tree structure being built, the program also needs a reference table so it can search this tree for particular keys. A direct search of the tree might work, but from experience this is very slow. The module CSymbol is used to create a hashed symbol table of each of the keys found in the file. In this way, a very quick search can find the nth appearance of any key in the file.

Mac OS X Panther for Unix Geeks

Related Reading

Mac OS X Panther for Unix Geeks
Apple Developer Connection Recommended Title
By Brian Jepson, Ernest E. Rothman

makefile Construction

The module CMaker is where the rubber meets the road and the actual makefile is constructed. This module is run after the symbol table and tree representation of the project file are completed. To build the makefile two things have to be found: a list of the .H files and a list of the .C (or CP) files. You can see these in the product makefile. Once you know these, then:

  • The INCLUDE list comes from the path lists to the .H files.
  • The main dependency <name> : <Filename>.o comes from the list of .C/CP files.
  • The main link list and each of the individual file-builds come from the .C list.

I've found in the project file the VALUE of an isa key of PBXSourcesBuildPhase denotes the list of .C files and PBXHeadersBuildPhase denotes the list of .H files. It is then a matter of finding these lists in the memory tree representation of the project file and building file lists.

The rest of building the makefile is largely a matter of fprintf()s of the lists of data in various forms to the output makefile. This is also where, if you want another type of makefile it's quite easy to change the output.

Jim Schimpf does embedded software development for telecommunications test equipment and develops Mac freeware in his free time, while not doing his other job of tractor repair/general grunt work for his 200-acre farm.


Return to MacDevCenter.com.