How can I build a workspace scheme / pass arguments to xcodebuild?

2,458 views
Skip to first unread message

Mark Aufflick

unread,
Jul 10, 2012, 7:27:33 AM7/10/12
to frank-...@googlegroups.com
Hi all,

I am using KIF atm but am investing some time into researching Frank. I use a workspace with some sub-projects, so I need to frankify a particular scheme of a workspace. How do I pass the "-workspace" and "-scheme" arguments to xcodebuild without hacking frank?

Thanks,

Mark.

Peter Hodgson

unread,
Jul 11, 2012, 1:21:00 AM7/11/12
to frank-...@googlegroups.com
Hi Mark,

Can you try the pre-release frank-cucumber gem I just pushed. `gem install frank-cucumber --prerelease` should get you set up. Amongst other things this gem updates `frank build` to take optional --workspace, --scheme and --target flags. It passes the value of these flags through to the underlying xcodebuild command which frank build uses. Note that frank build wants flags with two dashes (--workspace), despite xcodebuild using single-dashed flags (-workspace). I'd have preferred to get frank build to work with single-dashed flags, but it was a bit of a hassle. Ce la vie.

Let me know if you run into any problems.

Cheers,
Pete

jon

unread,
Jul 11, 2012, 1:57:05 PM7/11/12
to frank-...@googlegroups.com
Hi, I just installed pre-release

I'm attempting to call frank build --scheme SchemeName   but i'm getting an error 'frank buidl required at least 0 argument: "frank build'."

jon

unread,
Jul 11, 2012, 4:54:27 PM7/11/12
to frank-...@googlegroups.com
n/m i cleaned out 0.9.4 and then updated my Gemfile to point at 0.9.5.pre1 and i get the build settings.  

I'm still having problems with the restkit submodule but that is a different thread.

Mark Aufflick

unread,
Jul 12, 2012, 7:56:14 PM7/12/12
to frank-...@googlegroups.com
Great news. I hit two problems, the first is you have an escaping problem with the scheme name that I worked around by duplicating the scheme and removing spaces. The second I get is this error during the build of one of the dependencies (in this case one of the Urban Airship libraries):

=== BUILD NATIVE TARGET InboxLib OF PROJECT InboxLib WITH CONFIGURATION Debug ===

=== BUILD NATIVE TARGET StoreFrontLib OF PROJECT StoreFrontLib WITH CONFIGURATION Debug ===

** BUILD FAILED **

/Users/aufflick/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/fileutils.rb:1252:in `mkdir': No such file or directory - Frank/frankified_build/Frankified.app/frank_static_resources.bundle (Errno::ENOENT)
from /Users/aufflick/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/fileutils.rb:1252:in `copy'
from /Users/aufflick/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/fileutils.rb:461:in `block in copy_entry'
from /Users/aufflick/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/fileutils.rb:1341:in `preorder_traverse'
from /Users/aufflick/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/fileutils.rb:458:in `copy_entry'
from /Users/aufflick/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/fileutils.rb:433:in `block in cp_r'
from /Users/aufflick/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/fileutils.rb:1423:in `block in fu_each_src_dest'
from /Users/aufflick/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/fileutils.rb:1439:in `fu_each_src_dest0'
from /Users/aufflick/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/fileutils.rb:1421:in `fu_each_src_dest'
from /Users/aufflick/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/fileutils.rb:432:in `cp_r'
from /Users/aufflick/.rvm/gems/ruby-1.9.2-p290@frank-fa2/gems/frank-cucumber-0.9.5.pre1/lib/frank-cucumber/cli.rb:61:in `block in build'
from /Users/aufflick/.rvm/gems/ruby-1.9.2-p290@frank-fa2/gems/thor-0.15.4/lib/thor/actions.rb:192:in `block in in_root'
from /Users/aufflick/.rvm/gems/ruby-1.9.2-p290@frank-fa2/gems/thor-0.15.4/lib/thor/actions.rb:182:in `block in inside'
from /Users/aufflick/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/fileutils.rb:121:in `chdir'
from /Users/aufflick/.rvm/rubies/ruby-1.9.2-p290/lib/ruby/1.9.1/fileutils.rb:121:in `cd'
from /Users/aufflick/.rvm/gems/ruby-1.9.2-p290@frank-fa2/gems/thor-0.15.4/lib/thor/actions.rb:182:in `inside'
from /Users/aufflick/.rvm/gems/ruby-1.9.2-p290@frank-fa2/gems/thor-0.15.4/lib/thor/actions.rb:192:in `in_root'
from /Users/aufflick/.rvm/gems/ruby-1.9.2-p290@frank-fa2/gems/frank-cucumber-0.9.5.pre1/lib/frank-cucumber/cli.rb:60:in `build'
from /Users/aufflick/.rvm/gems/ruby-1.9.2-p290@frank-fa2/gems/thor-0.15.4/lib/thor/task.rb:27:in `run'
from /Users/aufflick/.rvm/gems/ruby-1.9.2-p290@frank-fa2/gems/thor-0.15.4/lib/thor/invocation.rb:120:in `invoke_task'
from /Users/aufflick/.rvm/gems/ruby-1.9.2-p290@frank-fa2/gems/thor-0.15.4/lib/thor.rb:275:in `dispatch'
from /Users/aufflick/.rvm/gems/ruby-1.9.2-p290@frank-fa2/gems/thor-0.15.4/lib/thor/base.rb:425:in `start'
from /Users/aufflick/.rvm/gems/ruby-1.9.2-p290@frank-fa2/gems/frank-cucumber-0.9.5.pre1/bin/frank:5:in `<top (required)>'
from /Users/aufflick/.rvm/gems/ruby-1.9.2-p290@frank-fa2/bin/frank:19:in `load'
from /Users/aufflick/.rvm/gems/ruby-1.9.2-p290@frank-fa2/bin/frank:19:in `<main>'

Mark Aufflick

unread,
Jul 12, 2012, 7:59:00 PM7/12/12
to frank-...@googlegroups.com
I tried manually creating that directory but it didn't help

Stewart Gleadow

unread,
Jul 12, 2012, 8:52:33 PM7/12/12
to frank-...@googlegroups.com
Mark,

I've got the same error message, I think the reason it can't find those files is because of an error above though. I'm not getting Frank/frankified_build output, maybe because of this error:

/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: -dynamic not specified, -all_load invalid
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: -dynamic not specified the following flags are invalid: -ObjC -ObjC 
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: can't locate file for: -lShelley
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: file: -lShelley is not an object file (not allowed in a library)
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: can't locate file for: -lFrank
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: file: -lFrank is not an object file (not allowed in a library)
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool: can't open file: Frank (No such file or directory)
Command /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/libtool failed with exit code 1

- Stew

Peter Hodgson

unread,
Jul 12, 2012, 8:56:56 PM7/12/12
to frank-...@googlegroups.com
If you're running the same stuff I am, the reason this is failing is because it's building the RestKit library in the RestKit directory, so that relative reference to -LFrank is not working.

I fixed that by passing an absolute path, but that leads to the next error - duplicate symbols. The RestKit library is built with Shelley and Frank linked in, and then the app target is built with RestKit linked in but also with Shelley and Frank linked in again, which means duplicate symbol errors. This I don't think is solveable without my FRANK_LD_FLAGS hack I discussed earlier.

Hari B

unread,
Jul 12, 2012, 10:04:05 PM7/12/12
to Frank
Not sure if this will work for everyone.
I got around this issue by removing the "the magic - implicit
dependencies" Xcode maintains and build the libs and project
separately. I understand it defeats the purpose of having the "xCode
scheme" and everything, but i do like to have my own build structure
and dependency map explicitly.

--
Hari
> >> /Users/aufflick/.rvm/rubies/**ruby-1.9.2-p290/lib/ruby/1.9.**1/fileutils.rb :1252:in
> >> `mkdir': No such file or directory - Frank/frankified_build/**
> >> Frankified.app/frank_static_**resources.bundle (Errno::ENOENT)
> >>  from /Users/aufflick/.rvm/rubies/**ruby-1.9.2-p290/lib/ruby/1.9.**1/fileutils.rb :1252:in
> >> `copy'
> >> from /Users/aufflick/.rvm/rubies/**ruby-1.9.2-p290/lib/ruby/1.9.**1/fileutils.rb :461:in
> >> `block in copy_entry'
> >>  from /Users/aufflick/.rvm/rubies/**ruby-1.9.2-p290/lib/ruby/1.9.**1/fileutils.rb :1341:in
> >> `preorder_traverse'
> >> from /Users/aufflick/.rvm/rubies/**ruby-1.9.2-p290/lib/ruby/1.9.**1/fileutils.rb :458:in
> >> `copy_entry'
> >>  from /Users/aufflick/.rvm/rubies/**ruby-1.9.2-p290/lib/ruby/1.9.**1/fileutils.rb :433:in
> >> `block in cp_r'
> >> from /Users/aufflick/.rvm/rubies/**ruby-1.9.2-p290/lib/ruby/1.9.**1/fileutils.rb :1423:in
> >> `block in fu_each_src_dest'
> >>  from /Users/aufflick/.rvm/rubies/**ruby-1.9.2-p290/lib/ruby/1.9.**1/fileutils.rb :1439:in
> >> `fu_each_src_dest0'
> >> from /Users/aufflick/.rvm/rubies/**ruby-1.9.2-p290/lib/ruby/1.9.**1/fileutils.rb :1421:in
> >> `fu_each_src_dest'
> >>  from /Users/aufflick/.rvm/rubies/**ruby-1.9.2-p290/lib/ruby/1.9.**1/fileutils.rb :432:in
> >> `cp_r'
> >> from /Users/aufflick/.rvm/gems/**ruby-1.9.2-p290@frank-fa2/**
> >> gems/frank-cucumber-0.9.5.**pre1/lib/frank-cucumber/cli.**rb:61:in
> >> `block in build'
> >>  from /Users/aufflick/.rvm/gems/**ruby-1.9.2-p290@frank-fa2/**
> >> gems/thor-0.15.4/lib/thor/**actions.rb:192:in `block in in_root'
> >> from /Users/aufflick/.rvm/gems/**ruby-1.9.2-p290@frank-fa2/**
> >> gems/thor-0.15.4/lib/thor/**actions.rb:182:in `block in inside'
> >>  from /Users/aufflick/.rvm/rubies/**ruby-1.9.2-p290/lib/ruby/1.9.**1/fileutils.rb :121:in
> >> `chdir'
> >> from /Users/aufflick/.rvm/rubies/**ruby-1.9.2-p290/lib/ruby/1.9.**1/fileutils.rb :121:in
> >> `cd'
> >>  from /Users/aufflick/.rvm/gems/**ruby-1.9.2-p290@frank-fa2/**
> >> gems/thor-0.15.4/lib/thor/**actions.rb:182:in `inside'
> >> from /Users/aufflick/.rvm/gems/**ruby-1.9.2-p290@frank-fa2/**
> >> gems/thor-0.15.4/lib/thor/**actions.rb:192:in `in_root'
> >>  from /Users/aufflick/.rvm/gems/**ruby-1.9.2-p290@frank-fa2/**
> >> gems/frank-cucumber-0.9.5.**pre1/lib/frank-cucumber/cli.**rb:60:in
> >> `build'
> >> from /Users/aufflick/.rvm/gems/**ruby-1.9.2-p290@frank-fa2/**
> >> gems/thor-0.15.4/lib/thor/**task.rb:27:in `run'
> >>  from /Users/aufflick/.rvm/gems/**ruby-1.9.2-p290@frank-fa2/**
> >> gems/thor-0.15.4/lib/thor/**invocation.rb:120:in `invoke_task'
> >> from /Users/aufflick/.rvm/gems/**ruby-1.9.2-p290@frank-fa2/**
> >> gems/thor-0.15.4/lib/thor.rb:**275:in `dispatch'
> >>  from /Users/aufflick/.rvm/gems/**ruby-1.9.2-p290@frank-fa2/**
> >> gems/thor-0.15.4/lib/thor/**base.rb:425:in `start'
> >> from /Users/aufflick/.rvm/gems/**ruby-1.9.2-p290@frank-fa2/**
> >> gems/frank-cucumber-0.9.5.**pre1/bin/frank:5:in `<top (required)>'
> >>  from /Users/aufflick/.rvm/gems/**ruby-1.9.2-p290@frank-fa2/bin/**frank:19:in
> >> `load'
> >> from /Users/aufflick/.rvm/gems/**ruby-1.9.2-p290@frank-fa2/bin/**frank:19:in
> >> `<main>'
>
> >> On Wednesday, 11 July 2012 15:21:00 UTC+10, Pete Hodgson wrote:
>
> >>> Hi Mark,
>
> >>> Can you try the pre-release frank-cucumber gem I just pushed. `gem
> >>> install frank-cucumber --prerelease` should get you set up. Amongst other
> >>> things this gem updates `frank build` to take optional --workspace,
> >>> --scheme and --target flags. It passes the value of these flags through to
> >>> the underlying xcodebuild command which frank build uses. Note that frank
> >>> build wants flags with two dashes (--workspace), despite xcodebuild using
> >>> single-dashed flags (-workspace). I'd have preferred to get frank build to
> >>> work with single-dashed flags, but it was a bit of a hassle. Ce la vie.
>
> >>> Let me know if you run into any problems.
>
> >>> Cheers,
> >>> Pete
>

Stewart Gleadow

unread,
Jul 13, 2012, 2:35:15 AM7/13/12
to frank-...@googlegroups.com
On the implicit dependencies... I've never had them work reliably, so I always set up explicit project and target dependencies.

I've had a play around with using separate variable names. It's up on my Frank fork on a branch called easy-install-xcconfig-fixes: https://github.com/sgleadow/Frank/tree/easy-install-xcconfig-fixes and pull request at https://github.com/moredip/Frank/pull/117. It looks like more work than it actually is, it basically comes down to tweaking 3 build settings.

The changes I needed to make to Frank:

- build_output_dir needed to be absolute, because my workspaces have projects in nested directories, and some things were relative to the workspace and others were relative to the project. Absolute path fixed that.

- the library search path also needed to be absolute (to find libFrank.a and libShelley.a), so I fed that through in a separate variable, rather than "-L Frank", called FRANK_LIBRARY_SEARCH_PATHS

- use a different variable name for the linker flags (FRANK_LDFLAGS). Since most projects I work on also have -all_load and -ObjC added, these are duplicated in the final compile but seem pretty harmless

- when running xcodebuild, I changed it to run both the 'build' and 'install' action. When running install, the headers and libs for dependent projects go into strange places and the header search paths don't find them. This answer (http://stackoverflow.com/a/5607353/223558) suggests hardcoding some header paths, I prefer to just also run the 'build' action, where headers go to the right place

The changes I needed to make to my project:

- made sure SKIP_INSTALL was set to NO... this isn't related to my changes, but for some reason I had it to YES which results in the 'install' action not copying files to the right place, as Luke Redpath found out last night https://twitter.com/lukeredpath/statuses/223402779262189570

- joined in the Frank linker and search path flags into the build settings for my main target:

OTHER_LDFLAGS = $(inherited) $(FRANK_LDFLAGS)
LIBRARY_SEARCH_PATHS = $(inherited) $(FRANK_LIBRARY_SEARCH_PATHS)

- linked up the APP_NAME parameter to default to the TARGET_NAME when running from Xcode (as it did before implicitly anyway), but to allow it to be overridden for the Frankified build and not clash with any dependent apps:

APP_NAME = $(TARGET_NAME) // this gets clobbered by the Frank xcconfig when running from frank build
PRODUCT_NAME = $(APP_NAME)

- Something just for me, probably: I also used the PRODUCT_NAME to link to Info.plist and .pch dynamically (because I have some general xcconfigs I use for multiple projects). You probably don't have this problem, but if you do, obviously these filenames don't change to Frankified-Info.plist... the solution is to use TARGET_NAME directly rather than PRODUCT_NAME, since this doesn't change

- Another one just for me: my unit tests compile during the same build, and it needs the BUNDLE_LOADER and TEST_HOST to link to the app being compile, it also needs to be linked to APP_NAME. I expect most people have a separate test scheme, so wont have this problem

APP_NAME = MyAppNameInXcode // gets clobbered by frank xcconfig
BUNDLE_LOADER = $(BUILT_PRODUCTS_DIR)/$(APP_NAME).app/$(APP_NAME)
TEST_HOST = $(BUNDLE_LOADER)

cheers,
Stew

Peter Hodgson

unread,
Jul 13, 2012, 2:55:34 PM7/13/12
to frank-...@googlegroups.com
Stew you are an absolute star. This looks like we're on the right track. 

I made one extra change to get rid of the need for APP_NAME and then merged this in. I also switched to using install rather than build as it sounded like using install was causing more headaches. Let me know if my change was a bad thing.

I've also pushed a new pre-release gem containing these improvements: frank-cucumber -v 0.9.5.pre2

Using a test project I only needed to make two of the changes you mentioned below; adding the following to the app target:
OTHER_LDFLAGS = $(inherited) $(FRANK_LDFLAGS)
LIBRARY_SEARCH_PATHS = $(inherited) $(FRANK_LIBRARY_SEARCH_PATHS)

everything else worked out of the box for me.

I'm working now on getting those two manual changes to the xcode project automated during the `frank setup` phase.

Cheers,
Pete

Stewart Gleadow

unread,
Jul 15, 2012, 7:03:44 PM7/15/12
to frank-...@googlegroups.com
Hi Pete,

Just having a crack at lastest master (0.9.5.pre4)... I get the following error on 'frank setup':

/Users/sgleadow/.rvm/gems/ruby-1.9.3-p0@conference/gems/frank-cucumber-0.9.5.pre4/lib/frank-cucumber/frankifier.rb:33:in `decide_on_project': There are no .xcodeproj files in this directory. Please move to your root project directory and try again. (RuntimeError)

The issue is probably that I only have MyWorkspace.xcworkspace at the top level, and then a directory for each dependent project. I don't see an easy way of knowing which project to select unless I provide it as an argument... actually, given the project could have multiple targets as well, is it best to provide workspace/project/target as arguments?

- Stew

Peter Hodgson

unread,
Jul 15, 2012, 10:05:37 PM7/15/12
to frank-...@googlegroups.com
Hey Stew,

Yes, my solution was a bit of a "Minimum Viable Product".

As far as I can see (and I could well be missing something here), the changes we need to make in order to Frankify an app only ever need to touch the app's target. That means you should be able to work around this for now by changing into the directory which holds your app's .xcodeproj file and then running `frank setup` from there (choosing the correct target if needed).

Obviously that workaround is not the ideal end state. Maybe a good approach would be to scan the current directory and all subdirectories for .xcodeproj files and then ask the user to select the correct one. FWIW I feel like this is a slightly nicer experience than asking the user to pass that information in the command line. I'm not sure we even have to mess with workspace files at all. 

Does anyone else have ideas for a nicer or less confusing or more user-friendly approach? All opinions and ideas gratefully received.

Cheers,
Pete

Mark Aufflick

unread,
Jul 16, 2012, 2:31:32 AM7/16/12
to frank-...@googlegroups.com
You can't avoid the workspace file if the project relies on the implicit dependencies. For straight-forward use of external submodules (as opposed to tightly coupled modules) the implicit dependencies work great. Anecdotally they are getting increasing use so I think they will need to be handled at some point.

The project I am hoping to use Frank on first only has two simple dependencies so for now I'm going to statically include .a files, but with other projects that's not going to work. At that point I might get my hands dirty :)
Reply all
Reply to author
Forward
0 new messages