Back in 2006 I posted a forum question seeking help with embedding a command line tool inside a Cocoa application. After a few days I had muddled out a way to both embed the command line tool and set up Xcode to automatically build the command line tool when the Cocoa wrapper is rebuilt. I posted my solution answering my own question.
Recently I received a message from someone who stumbled on my solution and found it useful. I’m reposting the solution here so that this information does not get lost.
My original question:
Poking around in the package contents for a few applications I’ve noticed that it is not uncommon for developers to package up small command line tools within the main Cocoa application. Presumably these command line tools are executed as a new process from the Cocoa application.
I’m developing in Xcode and have manged to import the source code for the command line tool as say command_line.c
. What do I need to do to have this file built as a command line tool that is embedded in the main Cocoa application?
My solution:
(Warning: Long and technical post.)
MyCocoaApp.app/ Info.plist Contents/ MacOS/ MyCocoaApp some_command_line_tool PkgInfo/ ...
Where MyCocoaApp
is the main Cocoa executable for this application and some_command_line_tool
is a standard BSD C application coded to know nothing about Objective-C or Cocoa.
After creating a Cocoa application project for MyCococaApp.app
in Xcode the steps below will add the command line tool into the project.
First we need to add the source files for some_command_line_tool
into the Xcode project. In this example the command line tool is implemented in one file named some_command_line_tool.c
.
- Click to highlight the project group for
MyCocoaApp
in Xcode. This is the first item in the Groups & Files tree view. - Right-click (control-click) on the project group and select the Add->New File… option from the context menu.
- Select BSD C File in the File Assistant and click Next.
- Specify a name for the file, in this example the name is
some_command_line_tool.c
. - Accept the default location and select the
MyCocoaApp
from the Add to Project drop-down. - Do not select any Targets.
- Click Finish.
Now we need to tell Xcode about this new command line by setting up a new target for it. This target will compile the some_command_line_tool.c
file to produce the some_command_line_tool
executable.
- Double-Click to expand the Targets group in the Groups & Files tree view.
- Right-Click (control-click) on the Targets group and select the Add->New Target.. option from the context menu.
- Select BSD->Shell Tool in the Target Assistant and click Next
- Specify a name for the target, in this example the name is
some_command_line_tool
. - Select the
MyCocoaApp
project from the Add to Project drop-down. - Click Finish.
- Close the Target Info window that opens.
You can now select the some_command_line_tool
as the active target from the project menu and open some_command_line_tool.c
to hack away at implementing the command line tool and testing it. Once you have it implemented, set the active target for the project back to the Cocoa target MyCocoaApp
and continue with these instructions.
Since our Cocoa application will invoke the command line tool we want to set up a dependency between the Cocoa application target and the command line tool target. This dependency will ensure that whenever the Cocoa application target is built then the command line tool will also be built.
- Right-Click (control-click) on the
MyCocoaApp
target and select the Get Info option. - In the Target Info window that pops up select the General tab.
- Click on the + button at the bottom of the window and add the command line tool target from the pop-up list.
- Close the Target Info window.
Now, if you select the Project group and select Build->Clean All Targets from the menubar followed by a build on the MyCocoaApp
target you should notice that the some_command_line_tool
is also built.
The remaining step is to automate copying the some_command_line_tool
executable file into the correct place in the MyCococaApp.app
bundle. This is done by adding a new build phase to the MyCococaApp
target.
- Right-Click (control-click) on the
MyCocoaApp
target and select the Add->New Build Phase->New Copy Files Build Phase option. - You want to copy an executable file so set the Destination to be Executable in the pop-up window. Do not specify a Path. The Destination setting means that the files copied in this phase will be copied to
Contents/MacOS
in the Cocoa application bundle. The Path setting is to specify a sub-path below theMacOS
folder. - Close the Copy Files Phase Info window.
- Double-click to expand the
MyCocoaApp
target and notice the Copy Files target at the bottom of the build phases. - Click to highlight the project group for
MyCocoaApp
. - Find your
some_command_line_tool
executable file in the right side of the window and drag-and-drop the file onto the new Copy Files phase in theMyCocoaApp
target. - Clean and build the Cocoa application target.
If you now use the Finder or Terminal to navigate to the build folder in your Xcode project folder you will find the Cocoa application. Navigating into the package contents for the application should show both MyCocoaApp
and some_command_line_tool
executables in the MacOS
folder.
Just happened across this by way of Google. This answers an amazing amount of questions I’ve been trying like heck to find the answers to. A million thanks to you! Simply awesome.
You’re welcome. Before I posted to the forums I’d spent a few days searching on Google to work out how to do this. Another couple of hours poking at Xcode resulted in the answer I posted here.
There may be other (or better) approaches, but this one seemed to work at the time of writing (2006). I’m not sure how much of the Xcode interface has changed since then but the report from Scott S suggests that the interface is similar enough that the instructions still have use. 🙂
Pingback: Stack Overflow